互联网为什么需要后端
本文最后更新于10 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

按照传统定义,服务器就是一台计算机,它专门监听发往开放端口的请求,比如HTTP、WebSocket,GRPC等等、无论是什么端口,只要端口可以通过互联网访问,所以其他计算机就可以通过其连接到他

为什么我们不能把所有后端逻辑都写在前端?

刚开始学 Web 的时候其实很容易产生一个疑问:既然 JavaScript 已经可以发送 HTTP 请求,浏览器也提供了 fetch、WebSocket 等 API,那为什么还需要后端?前端直接请求数据库、第三方 API,甚至把所有业务逻辑都写进浏览器里,不是少了一层,架构还更简单吗?

问题在于,前端运行在用户的电脑上,而后端运行在我们控制的服务器上。这两个运行环境的区别,决定了很多事情根本不能放心交给前端。

1. Security:前端是一个完全不可信的环境

这是最重要的一点。

我们写:

fetch("/api/user")

虽然代码是我们写的,但真正执行这段代码的机器属于用户。用户可以打开 DevTools 看代码、修改 JavaScript、抓 HTTP 请求,甚至完全绕开网页,自己用 Postman、curl 或脚本构造请求。

所以不能认为:

「我的前端页面没有这个按钮,用户就不能执行这个操作。」

例如管理员后台里有:

if (user.role === "admin") {
    showDeleteButton();
}

把按钮隐藏起来只能改变 UI,并不能真正保护数据。

如果真正的删除接口:

DELETE /api/users/123

没有在后端再次判断「这个请求者到底是不是管理员」,攻击者完全可以绕开页面直接请求这个接口。

更严重的是各种密钥。

假设前端代码里直接写:

const API_KEY = "sk-xxxxxxxx";

这个 Key 基本就等于公开了。因为 JavaScript 最终必须下载到用户浏览器才能执行,所以无论怎么打包、压缩甚至混淆,都不能把真正的秘密安全地藏在前端。

这也是为什么数据库密码、服务器凭证、第三方服务 Secret、支付密钥等东西必须留在后端。

所以这里可以记一个非常重要的 Web 开发原则:

前端负责交互,但永远不能作为最终的安全边界。真正的身份认证、权限校验和敏感业务规则必须由服务器执行。


2. CORS:浏览器不会允许网页随便读取其他网站的数据

这里特别容易和反向代理混在一起。

假设我的网站运行在:

https://myblog.com

前端突然执行:

fetch("https://api.example.com/data")

这时候浏览器会发现:

网页来源:myblog.com
请求目标:api.example.com

它们不是同一个 Origin(源)

Origin 主要由:

协议 + 主机 + 端口

决定。

浏览器受到同源策略(Same-Origin Policy)的限制,不会允许 JavaScript 毫无限制地读取其他源的数据。

如果 api.example.com 希望允许 myblog.com 的网页访问,它需要通过响应头明确告诉浏览器,例如:

Access-Control-Allow-Origin: https://myblog.com

复杂一些的请求甚至可能先出现:

OPTIONS /api/data

也就是 CORS Preflight(预检请求)

所以 CORS 更准确的理解应该是:

不是前端“有没有把请求头配完整”的问题,而是目标服务器通过 CORS 响应头告诉浏览器:我是否允许这个来源的网页读取我的响应。

而且有个很容易误解的地方:

CORS 主要是浏览器施加的安全机制,不等于服务器本身拒绝了这个 HTTP 请求。

所以你可能遇到一种很经典的情况:

Postman 请求:成功
curl 请求:成功
后端请求:成功

浏览器 fetch:CORS Error

因为前三者没有浏览器的同源策略限制。

前端虽然可以通过 fetch 等 Web API 请求网络资源,但它并不像后端一样,可以自由地向任意服务器发起请求并读取结果。前端 JavaScript 运行在浏览器的安全环境中,受到同源策略和 CORS 的约束。

例如我们的网页运行在:

https://myapp.com

现在前端想直接获取:

https://api.example.com/data

即使我们知道这个 API 地址,也知道应该传什么参数:

fetch("https://api.example.com/data")

浏览器依然会检查这个跨域请求是否被目标服务器允许。如果对方没有允许 myapp.com 这个来源,前端代码本身并不能强行绕过这个限制。

这就是关键区别:

浏览器前端
   ↓
受到同源策略 / CORS 限制
   ↓
第三方服务器

而如果由我们的后端去请求:

浏览器
   ↓
自己的后端
   ↓
第三方服务器

服务器之间的 HTTP 请求不受浏览器 CORS 机制约束。

因此,假如一个应用需要整合多个数据源:

天气 API ─────┐
地图 API ─────┤
支付 API ─────┼──→ Backend ──→ Frontend
内部服务 A ───┤
内部服务 B ───┘

如果把这些工作全部扔给前端,那么前端不仅要分别处理这些 API,而且会受到各个服务的跨域策略限制;有些服务甚至根本不允许浏览器直接调用。

而交给后端以后,后端可以主动请求这些服务,对数据进行组合、加工,再通过自己的 API统一返回给前端。

前端的网络能力是浏览器“批准给你的”,后端的网络能力则是服务器自己拥有的。CORS 就是这种能力差异最典型的体现之一。


3. Database:浏览器不应该直接连接数据库

这个问题其实比前两个更加直观。

假设我们不用后端,让 React 直接连接 MySQL:

浏览器
   ↓
MySQL

那么首先就出现一个无法回避的问题:

数据库账号和密码放哪?

放前端?

那用户打开 DevTools:

host = db.example.com
username = root
password = 123456

恭喜,数据库基本可以准备跑路了。

即使暂时不考虑安全,还有连接管理问题

数据库连接不是完全没有成本的。建立连接涉及网络通信、认证、数据库资源占用等过程。如果:

10000 个用户
       ↓
每个浏览器自己连接数据库
       ↓
10000+ 数据库连接

数据库压力会非常大,而且你根本无法很好地控制这些连接。

所以通常变成:

10000 个用户
       ↓
    HTTP 请求
       ↓
      后端
       ↓
    Connection Pool
       ↓
     Database

所谓 Connection Pool(数据库连接池),可以先理解成:

后端提前维护一批可以重复使用的数据库连接,请求来了借一个,用完以后还回池子,而不是每次请求都重新创建一个数据库连接。

比如:

Request A ─┐
Request B ─┤
Request C ─┤
Request D ─┼──→ 后端 ──→ [ DB Connection Pool ] ──→ MySQL
Request E ─┤                 │ │ │ │ │
...        │                 复用有限数量的连接
10000用户 ─┘

这样后端就成了数据库前面的一层控制面:可以控制谁能查询、能查询什么、一次查多少、连接数量是多少,还可以做事务、缓存、限流等。


其实还有第 4 个问题:Business Logic

从「为什么需要后端」这个问题继续往下推,还有一个非常核心的原因:业务规则必须有一个可信的执行位置。

例如购物网站下单:

商品价格:¥100
优惠券:-¥20
库存:剩 1 件
最终支付:¥80

如果这些全部由前端决定:

const finalPrice = price - discount;

用户完全可以把它改成:

const finalPrice = 0.01;

然后告诉服务器:

{
  "product": 123,
  "price": 0.01
}

所以真正可靠的流程应该是:

前端:
我要买商品 123
使用优惠券 ABC

        ↓

后端:
商品 123 现在多少钱?
优惠券 ABC 是否有效?
这个用户能不能使用?
库存还有没有?
最终价格是多少?
创建订单

        ↓

数据库

也就是说,前端可以展示业务逻辑的结果,但关键业务逻辑最终必须由后端重新计算和验证。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇