记录开发过程中遇到的问题
浏览器的跨域预检
INFO: 127.0.0.1:54365 - “OPTIONS /usersrole=admin HTTP/1.1” 200 OK INFO: 127.0.0.1:54365 - “GET /usersrole=admin HTTP/1.1” 200 OK 为什么每次调用这个接口会有两个
• 这是浏览器的跨域预检 + 实际请求各一次:
- 前端带 Authorization 头、跨域调用 /users?role=admin 时,浏览器会先发 OPTIONS 预检,看服务器是否允许该方法 头。你启用了 CORS,所以预检返回 200。
- 预检通过后才发真正的 GET /users?role=admin,所以日志里看到两条。
这是正常行为;非浏览器(如 curl/postman)或同源、无自定义头的请求则不会有预检。
如何解决跨源的问题
我们推导出了两套针对不同环境的最佳实践方案,核心逻辑都是“利用中间人(代理)实现同源”。
💻 开发环境 (Development)
- 工具: Vite (
server.proxy) - 原理: 利用 Vite 启动的 Node.js 服务转发请求。
- 效果: 浏览器只跟 Vite 打交道(同源),Vite 跟后端打交道(服务器间无 CORS 限制)。完美消除预检和跨域报错。
🚀 生产环境 (Production)
- 工具: Nginx (反向代理)
- 原理: 浏览器所有请求(页面 + 接口)统一发给
Nginx(比如 80 端口)。
/-> Nginx 返回静态 HTML/JS 文件。/api-> Nginx 转发给后端服务(8000 端口)。
- 效果: 在浏览器看来,它始终只访问了一个域名(同源),因此不需要 CORS 配置,也没有预检请求,性能最高。
Authorization 头是什么
Authorization 头(Header)是 HTTP
协议中用来验证用户身份的一个标准字段。
1. 标准格式
Authorization
头的值并不是随便填写的,它遵循一个严格的语法结构:
1 | Authorization: <认证类型> <凭证数据> |
- 认证类型 (Schema):
说明后面跟的是哪种类型的凭证(比如是“密码”还是“令牌”)。常见的有
Bearer和Basic。 - 空格: 中间必须有一个空格分隔。
- 凭证数据 (Credentials): 具体的加密字符串或 Token。
2. 最常用的两种类型
A. Bearer (最常见,用于 JWT)
这是目前现代 Web 应用和 API 最主流的方式,通常配合 JWT (JSON Web Token) 使用。
含义: “Bearer” 的意思是“持有者”。意思是:“谁持有这个令牌,谁就有权限。”
场景: 用户登录后,服务器发给用户一个 JWT。用户下次请求时,把这个 JWT 放在这里。
HTTP 请求示例:
HTTP
1
2
3GET /api/user/profile HTTP/1.1
Host: example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...注意: 这里的乱码字符串
eyJ...就是上一条回答中提到的 JWT。
B. Basic (最基础,用于用户名密码)
这是 HTTP 协议内置的最古老的认证方式。
含义: 直接把“用户名:密码”拼接,然后进行 Base64 编码传给服务器。
场景: 内部系统、简单的测试环境、或者某些传统的网关认证。
原理:
- 用户名
admin,密码123456。 - 拼接:
admin:123456。 - Base64 编码:
YWRtaW46MTIzNDU2。
- 用户名
HTTP 请求示例:
1
2POST /api/login HTTP/1.1
Authorization: Basic YWRtaW46MTIzNDU2