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

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

  •  
  •   skinny · 168 天前 · 2804 次点击
    这是一个创建于 168 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    注意,不是单页应用!

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

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

    • 服务端负责提供 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 条附言  ·  168 天前

    折中.png

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

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

    --------


    你说的这个叫前后端不分离
    zoharSoul
        3
    zoharSoul  
       168 天前   ❤️ 1
    @zoharSoul #2 你描述的想法是前后端不分离的,
    什么叫前后端分离? 意味着两者通过 api 来交互, 而不是后端返回 html

    从体验来看, 前后端分离后的前端和 c 端(app 端)的逻辑是一致的.
    你想想 android/ios 怎么处理你文中的这个需求:
    ```
    除了路由问题,前端页面的权限控制怎么做?比如有这样一个需求,某些页面只能特定用户访问,任何无权限用户不应该获取到这些页面的任何信息,即便无权限用户根本不能请求相关 API 。
    ```
    你就明白前后端分离的情况下, 这个职责是前端怎么处理了
    wunonglin
        4
    wunonglin  
       168 天前   ❤️ 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  
       168 天前
    你描述的恰恰是单页应用,不是前后端分离。前后端分离的定义很简单,数据的处理和储存跟页面的渲染分成不同的项目,前端调后端的 api 实现数据传输。
    另外你遇到的这些问题其他人早就遇到并做出解决方案了,比如 next 和 nuxt 。你可以直接拿来用或者参考他们的做法
    skinny
        6
    skinny  
    OP
       168 天前
    @jguo 我说的就是前端调用后端 API 啊,页面渲染和怎么渲染依然由前端的 react 或 vue 代码做,只是说加了个服务端控制路由和对特定页面进行权限控制。粗略看了下 next 和 nuxt ,看起来符合我的需求。
    wunonglin
        7
    wunonglin  
       168 天前
    @skinny #6 权限控制只需要后台返回对应 role 的 string array 或者 id array 。权限控制本质就是个开关。后台只需要告诉前端那些要开,剩下的事情由前端去控制开关即可
    corningsun
        8
    corningsun  
       168 天前   ❤️ 2
    如果从来没一个人写过前后端分离的项目,可以先找个项目学习下。

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

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