最近在写一个自己的小项目,是一个多页面应用,综合考量下,选择了前后端分离这种架构。
注意,不是单页应用!
某些问题可能有点简单,请多多包涵。
首先,我开始以为的前后端分离是这样的:

服务端负责提供 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 只做代理

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

一般不这么使用, 因为前后端模式都是组件化的, 你这么使用, 意味着很多单页面很容易处理的问题会变得复杂, 16 年左右我写过的一个程序大概是你说的这种---> 后台服务(n 个)---> 应用层---> API 层(路由权限在这里)---> Static Content(不能直接请求, 需要 API 服务器授权中间件)---> 前端(轻量化使用 jQuery), 另外路径和路由没啥关系, 完全可以任意映射. 核心问题是你为什么要这么做? 有什么好处?

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

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


你说的这个叫前后端不分离

#2 你描述的想法是前后端不分离的,
什么叫前后端分离? 意味着两者通过 api 来交互, 而不是后端返回 html
从体验来看, 前后端分离后的前端和 c 端(app 端)的逻辑是一致的.
你想想 android/ios 怎么处理你文中的这个需求:

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

你就明白前后端分离的情况下, 这个职责是前端怎么处理了

不要 SPA 又不要 MVC 。你这不是自找麻烦么。。。

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

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

如果你就真手写一个一个页面的话也不是不行,写一些公共的 js ,例如 service.js 、url-params.js 等,公共方法,每个页面引用然后获取参数然后发送请求获取数据手动操作 dom

你描述的恰恰是单页应用,不是前后端分离。前后端分离的定义很简单,数据的处理和储存跟页面的渲染分成不同的项目,前端调后端的 api 实现数据传输。
另外你遇到的这些问题其他人早就遇到并做出解决方案了,比如 next 和 nuxt 。你可以直接拿来用或者参考他们的做法

我说的就是前端调用后端 API 啊,页面渲染和怎么渲染依然由前端的 react 或 vue 代码做,只是说加了个服务端控制路由和对特定页面进行权限控制。粗略看了下 next 和 nuxt ,看起来符合我的需求。

#6 权限控制只需要后台返回对应 role 的 string array 或者 id array 。权限控制本质就是个开关。后台只需要告诉前端那些要开,剩下的事情由前端去控制开关即可

如果从来没一个人写过前后端分离的项目,可以先找个项目学习下。

推荐“林间有风”的开源项目: doc.cms.talelin.com/

单页应用不是单页面的应用,可以有多个界面的
随便下个 vue 等前后端分离的后台管理系统看看怎么写的,权限,菜单,url 跳转等都有

我们项目是这样做的 由于页面和后台服务是独立部署,所以我们权限这一块只控 api 权限,就算能找到页面,打开页面请求数据的时候也因为没有授权而没有数据,而且为了方便(就是懒+提高性能)所有 api 都是固定的,也就是不会存在 /order/{id} 这种通配路径,对外只暴露一个网关端口,权限或相关后续服务需要的信息都在网关处理,针对控权限也就这么几种情况
1.菜单通过数据库拉出来
2.按钮也是通过配置然后由前段进行控制显隐
3.即使他们能找到对应的页面或 api ,由于没有授权 ,也是拿不到数据的

谢谢

后端针对前端 html 进行限制可以使用 nginx+lua 脚本控制。

前后端分离不适合多页应用,当然可以强上 SSR

按照楼主的描述,其实楼主核心的问题还是没有解决。
如果是 api 返回页面内容你这种方案是可以的。
但楼主说的是静态页面,这种情况即使你在静态页面里添加了一个认证的 api 来控制显示,但实际上 html 也已经下载到客户的机器上了(例如 csdn 必须登录才能查看全文,就可以通过脚本去掉)

#12 我就是这个意思,当然也可以用其它技术替代,多加一层顺手的嘛 。我看了下楼上有人说的 next.js 的文档,就跟我说的这个差不多,不过用的是 node.js web 服务器来处理动态路由,乍看文档之下,如果我需要在这个框架控制特定页面的访问权限,需要编写一些代码。

你这相当于放弃后端和前端的成熟路由方案,转而使用 NGINX 实现路由。如果页面路由逻辑很简单还好,稍微加一些嵌套和通配符就不好做了。(比如你例子里面的)
能不能说说这么做的原因是啥呢?如果嫌弃 spa 首屏加载太慢,有很多优化手段。如果是为了 seo ,使用上面说的 SSR 就可以了

我没说必须使用 nginx 实现路由啊,如果我文字没有描述清楚,那张图可以补充一下。

所以我在问有没有更好的方法嘛,还有询问实际项目一般怎么弄,因为我根本不是干这个的,不了解这些,写自娱自乐的项目时刚好觉得这么做还不错就做了。

任意 url 返回 index.html ,由前端解析 url 后,自行请求 API

分离 不透过后端取得页面(非文章内容)
你要前端也干后端的事情那不就也是一把梭了 再多个后端几乎没意义 多重验证?
含内容的伺服器如果有复杂验证 那实现的也就是一个小后端

看你的项目类型吧,就像上面说的如果不追求 seo 那就直接 vite 做 spa ,开发体验很舒适。如果想要 seo 那就 nextjs 或者 nuxtjs ,看你是用 react 还是 vue 。
路由的话,几个库的 router 和这两个脚手架都封装的很好,可以充分满足你的需要。vue 的权限可以用路由钩子实现,react 路由直接是一个组件,添加一下权限逻辑封装一下就可以用了。

能问小项目为啥要使用“多页面应用”吗

我乐意

不是,前后端分离项目为啥要管地址栏的 url ?不是通过 api 来交互吗?我们公司现在用的方案是,后台管理页面提供一个路由配置界面,然后给角色授权的时候可以授权每个角色可以看到的路由,前端通过 api 接口请求当前用户能看到的路由。然后前端根据返回的路由进行动态渲染。

api 管的是数据操作和会话这些啊,也就是后端,前端页面是另一拨,前端也有路由规则啊,我帖子里可能说的不够清楚,我是既想要客户端渲染(至少大部分),还想要服务端的动态路由,更想更好的权限控制,比如客户端在访问某些页面时没有权限,那服务端就什么相关的都不给,直接返回 403 或重定向走。关于关注地址栏的 URL 是在这种全都要的情况下开始没有想清楚……完全有别的更好的解决办法……

那我说的这种方案就能解决。前端路由分为静态路由和动态路由两种。静态路由是直接写死在路由文件里面的;动态路由可以跟 api 接口返回结果来动态渲染路由,也就是说,如果 api 接口不返回某个路由,那么他是不能看到对应的页面的。

我知道啊,就是我有个需求有点变态,如果客户端没有权限,我连这部分的 html 和渲染代码都不返回,跟传统的那种服务端渲染一样,不过我想到办法了,next 和 nuxt 也接近需求,不过是不是你们认为的前后端分离就不知道了……

打个比方,后端是个合金保险箱保护的设备,看不到里面,按对密码才吐点东西出来,前端(浏览器)路由就像一层层的防弹玻璃墙,尽管外面的客户端拿不到东西,但是可以看透这一层层玻璃墙里的样子,尽管很多人觉得那些东西不重要,但我觉得重要,我认为只有按对了密码,对应的那层玻璃墙才应该透明。

单纯好奇而已,大可不必这回复态度吧。

后端不变,前端再套一个 node