V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
skinny
V2EX  ›  程序员

请问大家多页面应用怎么做前后端分离?资源定位和前端页面权限控制怎么做?实际项目里是怎么做的?

  •  
  •   skinny · 2022-01-12 12:44:38 +08:00 · 3536 次点击
    这是一个创建于 806 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在写一个自己的小项目,是一个多页面应用,综合考量下,选择了前后端分离这种架构。

    注意,不是单页应用!

    某些问题可能有点简单,请多多包涵。

    首先,我开始以为的前后端分离是这样的:

    • 服务端负责提供 API (包括权限验证、增删查改、会话)
    • 前端浏览器负责 UI 渲染和逻辑控制,前端相关的 js/css/html 等资源都是静态文件,可以放在 CDN

    然后我想到一个路由问题,比如客户端请求了一篇文章的 URL ,该怎么处理? 这里有两种路由格式:

    • /articles/#/1

      nginx 直接返回 /articles.html 或 /articles/index.html ,然后前端解析 hash 并请求相关资源,再渲染出来

    • /articles/1

      这种需要编写 nginx 规则来拆分 URL ,其它基本同上

    上面这些遇到简单结构的 URL 还好,但是结构化的复杂的 URL 就不好处理,比如获取用户 1 的文章 1 ,URL 为“/users/1/articles/1”,这种又该如何处理?我能想到的是仍然返回 /articles.html 或 /articles/index.html ,然后前端再根据制定的 URL 规则解析处理。

    除了路由问题,前端页面的权限控制怎么做?比如有这样一个需求,某些页面只能特定用户访问,任何无权限用户不应该获取到这些页面的任何信息,即便无权限用户根本不能请求相关 API 。

    综合上面的问题,我想到一个折中的办法:

    • API 服务端照旧

    • 编写一个“前端”服务端负责前端页面权限验证、管理路由规则,数据获取和操作仍然通过 API 服务。

      比如有这样一个页面“/users/{uid}/dashboard/user-details?uid=xxx”,服务端路由 handler 取得客户端的 token ,向 API 服务查询权限, 如果该用户具有某些已标记权限则返回该页面,否则返回 403 或重定向到某页面。

      这样前端服务器仍然可以选择和 API 服务器不一样的技术,可以使用 node 一把梭,也可以用 openresty ,还可以用其它的技术。

    • nginx 只做代理

    最后,有更好的办法吗?你们的实际项目又是怎么做的?

    第 1 条附言  ·  2022-01-12 14:07:50 +08:00

    折中.png

    30 条回复    2022-01-14 15:43:11 +08:00
    thinkershare
        1
    thinkershare  
       2022-01-12 13:03:21 +08:00   ❤️ 1
    一般不这么使用, 因为前后端模式都是组件化的, 你这么使用, 意味着很多单页面很容易处理的问题会变得复杂, 16 年左右我写过的一个程序大概是你说的这种---> 后台服务(n 个)---> 应用层---> API 层(路由权限在这里)---> Static Content(不能直接请求, 需要 API 服务器授权中间件)---> 前端(轻量化使用 jQuery), 另外路径和路由没啥关系, 完全可以任意映射. 核心问题是你为什么要这么做? 有什么好处?
    zoharSoul
        2
    zoharSoul  
       2022-01-12 13:06:25 +08:00   ❤️ 4
    >>>
    首先,我开始以为的前后端分离是这样的:

    服务端负责提供 API (包括权限验证、增删查改、会话)
    前端浏览器负责 UI 渲染和逻辑控制,前端相关的 js/css/html 等资源都是静态文件,可以放在 CDN

    --------


    你说的这个叫前后端不分离
    zoharSoul
        3
    zoharSoul  
       2022-01-12 13:14:25 +08:00   ❤️ 1
    @zoharSoul #2 你描述的想法是前后端不分离的,
    什么叫前后端分离? 意味着两者通过 api 来交互, 而不是后端返回 html

    从体验来看, 前后端分离后的前端和 c 端(app 端)的逻辑是一致的.
    你想想 android/ios 怎么处理你文中的这个需求:
    ```
    除了路由问题,前端页面的权限控制怎么做?比如有这样一个需求,某些页面只能特定用户访问,任何无权限用户不应该获取到这些页面的任何信息,即便无权限用户根本不能请求相关 API 。
    ```
    你就明白前后端分离的情况下, 这个职责是前端怎么处理了
    wunonglin
        4
    wunonglin  
       2022-01-12 13:14:51 +08:00   ❤️ 1
    不要 SPA 又不要 MVC 。你这不是自找麻烦么。。。

    问:路由问题...
    答:这就是你自己用 nginx 实现一个类似于前端路由的功能罢了,不仅 nginx 需要对 url 处理以便于返回对应的 html ,页面也要对 url 处理用于获取 params 请求 api ,明摆了没事找事而已。更别说还想做权限控制等功能了,你非要说能不能做,我肯定回答你“能”,但是好不好做,麻不麻烦,你就自己掂量掂量了。

    问:折中的办法
    答:
    “前端服务端”,这不就是 SSR 么?用 vue 可以用 nuxt ,ng 可以用 universal 。

    如果你就真手写一个一个页面的话也不是不行,写一些公共的 js ,例如 service.js 、url-params.js 等,公共方法,每个页面引用然后获取参数然后发送请求获取数据手动操作 dom
    jguo
        5
    jguo  
       2022-01-12 13:52:01 +08:00
    你描述的恰恰是单页应用,不是前后端分离。前后端分离的定义很简单,数据的处理和储存跟页面的渲染分成不同的项目,前端调后端的 api 实现数据传输。
    另外你遇到的这些问题其他人早就遇到并做出解决方案了,比如 next 和 nuxt 。你可以直接拿来用或者参考他们的做法
    skinny
        6
    skinny  
    OP
       2022-01-12 14:17:19 +08:00
    @jguo 我说的就是前端调用后端 API 啊,页面渲染和怎么渲染依然由前端的 react 或 vue 代码做,只是说加了个服务端控制路由和对特定页面进行权限控制。粗略看了下 next 和 nuxt ,看起来符合我的需求。
    wunonglin
        7
    wunonglin  
       2022-01-12 14:23:16 +08:00
    @skinny #6 权限控制只需要后台返回对应 role 的 string array 或者 id array 。权限控制本质就是个开关。后台只需要告诉前端那些要开,剩下的事情由前端去控制开关即可
    corningsun
        8
    corningsun  
       2022-01-12 14:29:04 +08:00   ❤️ 2
    如果从来没一个人写过前后端分离的项目,可以先找个项目学习下。

    推荐“林间有风”的开源项目: https://doc.cms.talelin.com/
    james2013
        9
    james2013  
       2022-01-12 15:05:35 +08:00
    单页应用不是单页面的应用,可以有多个界面的
    随便下个 vue 等前后端分离的后台管理系统看看怎么写的,权限,菜单,url 跳转等都有
    freeup
        10
    freeup  
       2022-01-12 16:59:05 +08:00   ❤️ 1
    我们项目是这样做的 由于页面和后台服务是独立部署,所以我们权限这一块只控 api 权限,就算能找到页面,打开页面请求数据的时候也因为没有授权而没有数据,而且为了方便(就是懒+提高性能)所有 api 都是固定的,也就是不会存在 /order/{id} 这种通配路径,对外只暴露一个网关端口,权限或相关后续服务需要的信息都在网关处理,针对控权限也就这么几种情况
    1.菜单通过数据库拉出来
    2.按钮也是通过配置然后由前段进行控制显隐
    3.即使他们能找到对应的页面或 api ,由于没有授权 ,也是拿不到数据的
    skinny
        11
    skinny  
    OP
       2022-01-12 17:16:37 +08:00
    @freeup 谢谢
    zliea
        12
    zliea  
       2022-01-12 17:37:34 +08:00   ❤️ 1
    后端针对前端 html 进行限制可以使用 nginx+lua 脚本控制。
    pengtdyd
        13
    pengtdyd  
       2022-01-12 17:43:38 +08:00
    前后端分离不适合多页应用,当然可以强上 SSR
    zliea
        14
    zliea  
       2022-01-12 17:47:44 +08:00
    @freeup 按照楼主的描述,其实楼主核心的问题还是没有解决。
    如果是 api 返回页面内容你这种方案是可以的。
    但楼主说的是静态页面,这种情况即使你在静态页面里添加了一个认证的 api 来控制显示,但实际上 html 也已经下载到客户的机器上了(例如 csdn 必须登录才能查看全文,就可以通过脚本去掉)
    skinny
        15
    skinny  
    OP
       2022-01-12 18:33:12 +08:00
    @ztechstack #12 我就是这个意思,当然也可以用其它技术替代,多加一层顺手的嘛 。我看了下楼上有人说的 next.js 的文档,就跟我说的这个差不多,不过用的是 node.js web 服务器来处理动态路由,乍看文档之下,如果我需要在这个框架控制特定页面的访问权限,需要编写一些代码。
    lybcyd
        16
    lybcyd  
       2022-01-12 18:54:07 +08:00 via Android
    你这相当于放弃后端和前端的成熟路由方案,转而使用 NGINX 实现路由。如果页面路由逻辑很简单还好,稍微加一些嵌套和通配符就不好做了。(比如你例子里面的)
    能不能说说这么做的原因是啥呢?如果嫌弃 spa 首屏加载太慢,有很多优化手段。如果是为了 seo ,使用上面说的 SSR 就可以了
    skinny
        17
    skinny  
    OP
       2022-01-12 18:59:51 +08:00
    @lybcyd 我没说必须使用 nginx 实现路由啊,如果我文字没有描述清楚,那张图可以补充一下。
    skinny
        18
    skinny  
    OP
       2022-01-12 19:02:56 +08:00
    @lybcyd 所以我在问有没有更好的方法嘛,还有询问实际项目一般怎么弄,因为我根本不是干这个的,不了解这些,写自娱自乐的项目时刚好觉得这么做还不错就做了。
    joesonw
        19
    joesonw  
       2022-01-12 19:11:00 +08:00 via iPhone
    任意 url 返回 index.html ,由前端解析 url 后,自行请求 API
    james122333
        20
    james122333  
       2022-01-12 20:11:45 +08:00
    分离 不透过后端取得页面(非文章内容)
    你要前端也干后端的事情那不就也是一把梭了 再多个后端几乎没意义 多重验证?
    含内容的伺服器如果有复杂验证 那实现的也就是一个小后端
    lybcyd
        21
    lybcyd  
       2022-01-12 23:54:13 +08:00 via Android
    @skinny 看你的项目类型吧,就像上面说的如果不追求 seo 那就直接 vite 做 spa ,开发体验很舒适。如果想要 seo 那就 nextjs 或者 nuxtjs ,看你是用 react 还是 vue 。
    路由的话,几个库的 router 和这两个脚手架都封装的很好,可以充分满足你的需要。vue 的权限可以用路由钩子实现,react 路由直接是一个组件,添加一下权限逻辑封装一下就可以用了。
    Unicorns96
        22
    Unicorns96  
       2022-01-13 09:27:58 +08:00
    能问小项目为啥要使用“多页面应用”吗
    skinny
        23
    skinny  
    OP
       2022-01-13 09:38:08 +08:00
    @Unicorns96 我乐意
    itechnology
        24
    itechnology  
       2022-01-13 09:59:54 +08:00
    不是,前后端分离项目为啥要管地址栏的 url ?不是通过 api 来交互吗?我们公司现在用的方案是,后台管理页面提供一个路由配置界面,然后给角色授权的时候可以授权每个角色可以看到的路由,前端通过 api 接口请求当前用户能看到的路由。然后前端根据返回的路由进行动态渲染。
    skinny
        25
    skinny  
    OP
       2022-01-13 10:23:37 +08:00
    @itechnology api 管的是数据操作和会话这些啊,也就是后端,前端页面是另一拨,前端也有路由规则啊,我帖子里可能说的不够清楚,我是既想要客户端渲染(至少大部分),还想要服务端的动态路由,更想更好的权限控制,比如客户端在访问某些页面时没有权限,那服务端就什么相关的都不给,直接返回 403 或重定向走。关于关注地址栏的 URL 是在这种全都要的情况下开始没有想清楚……完全有别的更好的解决办法……
    itechnology
        26
    itechnology  
       2022-01-13 10:36:11 +08:00
    @skinny 那我说的这种方案就能解决。前端路由分为静态路由和动态路由两种。静态路由是直接写死在路由文件里面的;动态路由可以跟 api 接口返回结果来动态渲染路由,也就是说,如果 api 接口不返回某个路由,那么他是不能看到对应的页面的。
    skinny
        27
    skinny  
    OP
       2022-01-13 10:56:10 +08:00
    @itechnology 我知道啊,就是我有个需求有点变态,如果客户端没有权限,我连这部分的 html 和渲染代码都不返回,跟传统的那种服务端渲染一样,不过我想到办法了,next 和 nuxt 也接近需求,不过是不是你们认为的前后端分离就不知道了……

    打个比方,后端是个合金保险箱保护的设备,看不到里面,按对密码才吐点东西出来,前端(浏览器)路由就像一层层的防弹玻璃墙,尽管外面的客户端拿不到东西,但是可以看透这一层层玻璃墙里的样子,尽管很多人觉得那些东西不重要,但我觉得重要,我认为只有按对了密码,对应的那层玻璃墙才应该透明。
    Unicorns96
        28
    Unicorns96  
       2022-01-13 11:02:38 +08:00   ❤️ 1
    @skinny 单纯好奇而已,大可不必这回复态度吧。
    zachlhb
        29
    zachlhb  
       2022-01-13 15:57:32 +08:00
    后端不变,前端再套一个 node
    qfdk
        30
    qfdk  
       2022-01-14 15:43:11 +08:00 via iPhone   ❤️ 1
    next.js 满足你的需求. 它可以做 spa 活着 ssr 服务端渲染. 单独的页面也可以控制. 切实你需要一个鉴权请求, 如果请求过去用户有权限你就开放有权限的部分就好了. 没权限的直接 404. SPA 会有 token 存下来的 每个请求带着 token 请求. next 的 SSR 渲染 会先请求 再渲染页面. 里面你也可以用 api 文件夹 里面放上你后段逻辑. 建议看下文档 然后跑一下 应该满足你所有需求.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3260 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 11:54 · PVG 19:54 · LAX 04:54 · JFK 07:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.