前端开发如何独立解决跨域问题
Category(分类): NET Protocol Status: 未知
背景
跨域问题由浏览器同源策略引起。更准确地说,浏览器会限制一个源的脚本读取另一个源的响应。一个源由以下三部分组成:
scheme(协议) + host(主机) + effective port(有效端口)
因此,下面的地址互不完全同源:
http://localhost:3000
http://localhost:4000
http://127.0.0.1:3000
https://localhost:3000
前两个地址端口不同,第一和第三个地址主机不同,第一和第四个地址协议不同。即使 localhost 和 127.0.0.1 都指向本机,也不代表它们同源。
同源策略主要限制跨源脚本读取响应、访问跨源 DOM 和部分存储内容,并不阻止所有跨源网络请求。图片、脚本、表单等资源仍可能跨源加载或提交,服务器之间的请求也不受浏览器同源策略限制。

开发中常见的跨域方案包括:
- JSONP:利用
<script>可以加载跨源脚本的行为传递数据,但只能使用 GET,并且需要目标服务器支持; - CORS:由服务器通过响应头授权浏览器读取跨源响应;
- 代理或反向代理:让浏览器请求同源地址,再由代理服务器请求真正的后端接口。
JSONP 和 CORS 都需要目标服务配合。尤其是 CORS,服务端需要根据 Origin、请求方法、请求头和凭据策略返回正确的响应头。对于不能修改的线上接口,前端开发者通常可以在本地使用正向代理工具或反向代理服务器完成开发联调。
需要注意:代理工具是开发调试手段,不是绕过浏览器安全策略的生产方案;生产环境仍应由后端、网关或反向代理正确处理认证、权限、Cookie 和安全策略。
代理与反向代理
代理:正向代理
正向代理(Forward Proxy)位于客户端和目标服务器之间。客户端向代理发送请求,并指定希望访问的目标,代理再向目标服务器转发请求,把响应返回给客户端。

通俗地说
“客户端”可以看作食客,“目标服务器”可以看作一家饭店,“代理服务器”可以看作跑腿的小弟:
- 食客想吃饭店的酱排骨饭,就让小弟去饭店购买;
- 饭店把饭交给小弟;
- 小弟再把饭带给食客。
小弟代理了食客的请求,但目标饭店通常只直接看到代理服务器的连接。实际是否能隐藏客户端地址,还取决于代理是否转发了 Forwarded、X-Forwarded-For 等请求头。

数据流程
请求:浏览器 -> 正向代理 -> 目标服务器
响应:目标服务器 -> 正向代理 -> 浏览器
应用场景
正向代理可以用于:
- 企业内网通过统一出口访问互联网;
- 调试工具拦截、修改和转发开发请求;
- 缓存公共资源;
- 访问控制、审计和流量管理。
例如,国内用户访问某个无法直接访问的站点时,可以将浏览器配置为使用一个能够访问该站点的代理服务器。这里仅说明正向代理的网络原理,实际使用还需要遵守适用的法律、服务条款和网络管理规定。

反向代理
反向代理(Reverse Proxy)代表服务器接受互联网客户端的连接请求,再把请求转发给内部或上游服务器,最后将上游响应返回给客户端。

数据流程
请求:浏览器 -> 反向代理 -> 上游应用服务器
响应:上游应用服务器 -> 反向代理 -> 浏览器
通俗地说
“浏览器”可以看作食客,“反向代理服务器和后端服务器”这个整体可以看作饭店:
- 食客向服务员点菜;
- 服务员把订单交给厨师;
- 厨师做好菜后交给服务员;
- 服务员再把菜端给食客。
对外部客户端来说,通常只需要知道反向代理的域名,不需要知道具体是哪一台后端服务器提供服务。反向代理和上游服务器可以在同一台机器,也可以位于不同主机、不同网络或不同数据中心。
反向代理常用于:
- 负载均衡;
- TLS 终止;
- 静态资源处理;
- 缓存;
- 访问控制和限流;
- 统一转发多个后端服务。
正向代理与反向代理的比较
| 对比项 | 正向代理 | 反向代理 |
|---|---|---|
| 代表谁发起请求 | 代表客户端 | 代表服务器或服务集群 |
| 客户端是否通常知道代理 | 知道并配置代理 | 通常只看到统一入口 |
| 典型用途 | 内网出口、调试、缓存 | 负载均衡、网关、TLS、缓存 |
| 主要配置位置 | 客户端/操作系统和代理服务 | 服务端、网关或 Nginx |
| 是否能解决浏览器跨源读取 | 开发调试时可以改写请求路径 | 通过同源入口或 CORS 配置解决 |
利用正向代理进行本地开发
实现原理
使用 Charles、Fiddler 等正向代理工具时,可以配置 URL 映射:
- 访问静态页面时,把远程页面映射到开发者本机的资源;
- 访问 API 时,让请求继续发送到真实后端;
- 浏览器地址仍然使用目标域名,因此页面中的相对请求通常仍被浏览器视为同源。
这不是通过 JavaScript 绕过同源策略,而是代理在网络层改变了请求的实际去向。
程序运行过程
假设浏览器访问:
https://taobao.com/index.html
页面中请求:
https://taobao.com/api/getNew
通过正向代理映射后,流程可以是:
- 浏览器访问
taobao.com/index.html,请求先经过代理; - 代理根据规则,把页面请求转发到开发者本机,例如
http://127.0.0.1:3000/index.html; - 浏览器收到页面后,页面的 Origin 仍然是
https://taobao.com; - 页面请求
https://taobao.com/api/getNew,该请求再次经过代理; - 由于没有配置 API 映射,代理将请求转发给真实的淘宝服务器;
- 真实服务器按照
Host、TLS SNI、Cookie 和其他请求信息处理请求; - 代理把响应返回给浏览器,浏览器把它视为
taobao.com的响应。
这种方式适合本地调试同域页面和接口。它依赖代理工具运行,不适合直接作为线上用户的跨域解决方案。
Charles 配置示例
以 macOS 下的 Charles 为例,Windows 可以使用 Fiddler 或其他代理工具完成类似配置。
- 打开 Charles 的映射关系表:
Tools -> Map Remote。

- 点击
Add,添加远程映射规则。

- 在配置页面中设置源地址和目标地址。匹配规则越具体,越应优先于通配规则。例如
/api/*应放在整个域名/*规则之前,以免先被宽泛规则匹配。

- 点击帮助或问号图标,可以查看当前版本的配置说明。

- 如果要调试 HTTPS 请求,需要在开发设备和浏览器中安装并信任 Charles 根证书。安装代理根证书意味着 Charles 可以解密和重新签发被代理的 HTTPS 连接,只应在可信的开发环境中使用,调试完成后应删除或取消信任该证书。

- Chrome 通常会使用操作系统代理,但如果存在代理绕过规则、独立代理配置、HTTP/3/QUIC 不兼容或其他网络策略,请求可能不会出现在 Charles 中。需要检查系统代理、浏览器代理和协议支持情况。
- 微信开发者工具通常也需要单独配置代理:在设置中选择代理服务器,并确认其网络请求确实经过 Charles 或其他调试代理。

利用反向代理进行本地开发
反向代理是在服务器端处理请求。常见做法是使用一个开发域名,把它解析到本机,再由 Nginx 根据路径把静态资源和 API 请求分别转发到本地服务和真实后端。
实现原理
- 将开发域名解析到本机;
- Nginx 接收浏览器对该开发域名的请求;
- 静态资源请求转发到本地前端开发服务器;
- API 请求转发到真实后端;
- 浏览器始终请求同一个开发域名,因此不需要因为后端真实地址不同而触发浏览器 CORS。
开发时建议使用专用域名,例如:
127.0.0.1 app.local.test
不建议随意把正在使用的线上域名整体指向本机,因为这可能影响该域名下的其他资源、登录、WebSocket、CDN 和证书。
hosts 配置
在 hosts 文件中添加开发域名:
127.0.0.1 app.local.test

如果使用 HTTPS,还需要为 app.local.test 配置本地开发证书,并让浏览器信任该证书。仅修改 hosts 不会自动解决 TLS 证书校验问题。
Nginx 配置示例
下面假设:
- 前端开发服务器:
http://127.0.0.1:3000; - 真实 API 服务:
https://api.example.com; - 浏览器访问:
http://app.local.test。
server {
listen 80;
server_name app.local.test;
# 静态资源和前端页面转发到本地开发服务器
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# API 请求转发到真实后端
location /api/ {
proxy_pass https://api.example.com/;
proxy_ssl_server_name on;
proxy_ssl_name api.example.com;
proxy_set_header Host api.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
proxy_pass 是否带结尾 / 会影响 URI 的拼接方式,配置时要根据后端实际路由确认。若后端依赖虚拟主机,必须正确设置 Host;若上游使用 HTTPS,还要正确配置 SNI 和证书校验。

程序运行过程
- 浏览器访问
http://app.local.test/index.html; - hosts 将
app.local.test解析到127.0.0.1; - Nginx 接收到页面请求,并转发到
127.0.0.1:3000; - 浏览器运行页面,请求同源地址
http://app.local.test/api/getNew; - Nginx 根据
/api/规则,将请求转发给真实 API 服务; - API 服务返回数据给 Nginx;
- Nginx 再将响应返回给浏览器。
从浏览器角度看,请求始终访问 app.local.test,因此浏览器不需要读取 api.example.com 的跨源响应。
HTTPS、Cookie 和认证注意事项
- 本地 HTTPS 需要可信开发证书;
- Cookie 的 Domain、Path、Secure、SameSite 属性需要与开发域名匹配;
- 如果后端返回
Set-Cookie,反向代理可能需要改写 Cookie Domain 和 Path; Authorization、CSRF Token、Origin 等请求头应按照后端认证策略转发;- 代理不能因为“开发方便”而关闭所有 TLS 校验或无条件转发任意目标地址。
两种方案的对比
- Charles、Fiddler 等正向代理:配置相对直观,适合临时调试和查看请求;但依赖本机代理设置、根证书和工具运行状态。
- Nginx 反向代理:配置稍复杂,但规则稳定、可重复,也适合开发环境、测试环境和生产网关;需要理解 hosts、TLS、URI 转发、请求头和上游服务配置。
两者不是简单按照项目大小选择,而是根据使用场景选择:调试抓包适合正向代理,统一入口和长期环境配置更适合反向代理。
总结
前端独立解决开发阶段跨域问题,核心不是关闭浏览器同源策略,而是改变浏览器请求的路径:
- 使用正向代理工具时,代理可以把远程页面映射到本地资源,并把接口请求转发到真实服务;
- 使用反向代理时,浏览器请求本地或开发域名,Nginx 再把不同路径转发到本地前端或真实 API;
- 生产环境仍应优先使用服务端 CORS、同源反向代理和完善的认证授权配置;
- 不应依赖 JSONP、关闭证书校验或任意反射 Origin 等不安全方案。