前端跨域问题及解决方案
前端跨域问题及解决方案
YuXiang1. 为什么会出现跨域问题?
跨域(Cross-Origin)是指在浏览器中,出于安全考虑,网页的 JavaScript 脚本只能访问与当前页面同源的资源。同源策略(Same-Origin Policy)规定,只有协议、域名和端口都相同的请求才会被允许,否则会被浏览器阻止,这就是所谓的“跨域”问题。比如,当前网站是 https://www.wyxup.top JavaScript 向 http://api.wyxup.top 发送请求时,由于不同的域名或端口,浏览器会认为这是跨域请求。
1.1 同源策略
同源策略要求以下三个部分必须相同:
- 协议(Protocol):如
http
或https
。 - 域名(Domain):如
wyxup.top
。 - 端口(Port):如
80
或443
。
如果三者中有任何一个不同,就会触发跨域问题。
1.2 跨域示例
以下是一些跨域的示例:
- http://wyxup.top 和 https://wyxup.top(协议不同)。
- http://wyxup.top 和 http://api.wyxup.top(域名不同)。
- http://wyxup.top 和 http://wyxup.top:8080(端口不同)。
2. 跨域问题的错误代码
- CORS 错误:Access to XMLHttpRequest at ‘http://wyxup.top‘ from origin ‘http://localhost:4000‘ has been blocked by CORS policy。
- JSONP 错误:Uncaught SyntaxError: Unexpected token <。
3. 跨域解决方案
以下是常见的跨域解决方案:
3.1 CORS(跨域资源共享)
CORS(Cross-Origin Resource Sharing)是一种 W3C 标准,它允许浏览器向跨域服务器发送请求,并允许服务器通过设置 HTTP 响应头部来告知浏览器允许跨域请求。CORS 的核心机制是服务器通过响应头 Access-Control-Allow-Origin
指定允许访问的域名,浏览器根据该响应头来决定是否允许请求。
3.1.1 常见的 CORS 响应头
- Access-Control-Allow-Origin:指定允许的源(如 * 表示允许所有域,或者指定具体的域名)。
- Access-Control-Allow-Methods:允许的请求方法(如 GET, POST, PUT 等)。
- Access-Control-Allow-Headers:允许客户端携带的头部字段。
- Access-Control-Allow-Credentials:是否允许带有凭证(如 Cookies)的请求。
3.1.2 如何实现 CORS
- 服务器端需要设置响应头以允许跨域请求
- 如果是简单请求,浏览器会直接发送请求
- 对于复杂请求(如
PUT
、DELETE
,或者自定义请求头等),浏览器会先发送一个OPTIONS
预检请求,服务器需要响应以下头:
1 | Access-Control-Allow-Methods: GET, POST, PUT, DELETE |
1 | fetch('https://api.wyxup.top/data', { |
1 | // 服务器端响应头设置示例(以 Node.js 为例) |
3.2 JSONP(JSON with Padding)
JSONP 是一种通过 <script>
标签来绕过同源策略的老旧方案。它将跨域请求转化为对 JavaScript 代码的请求。通过服务器返回一段 JavaScript 代码,且这段代码执行时会调用一个回调函数,回调函数中包含需要的结果数据。
3.2.1 实现原理
- 前端通过 script 标签发送跨域请求,后端返回一个带有回调函数的 JavaScript 脚本。
- 前端回调该函数,并处理返回的数据。
3.2.2 示例代码
前端代码:
1 | function handleResponse(data) { |
服务器端代码(Node.js):
1 | const http = require('http'); |
3.2.3 局限性
- 仅支持GET请求。
- 安全性较低,容易受到 XSS 攻击。
3.3 代理(Proxy)
代理的做法是通过设置一个中间层(例如后端服务器或开发环境中的代理服务器)来转发请求,绕过浏览器的跨域限制。通过代理,前端请求实际上是发送到同源的服务器,服务器再将请求转发到跨域的目标服务器。
3.3.1 实现原理
- 前端请求同源服务器,同源服务器转发请求到目标服务器。
- 目标服务器返回数据,同源服务器再将数据返回给前端。
3.3.2 示例代码
使用 Node.js 实现代理服务器:
1 | const http = require('http'); |
前端代码:
1 | // webpack.config.js 配置代理 |
3.4 Nginx 反向代理
可以在后端服务器设置一个代理,将前端的请求转发给目标服务器,从而避免跨域问题。
3.4.1 配置示例
在 Nginx 配置文件中添加以下内容:
1 | server { |
前端直接请求 Nginx 服务器
3.5 WebSocket
WebSocket 作为一种长连接技术,不受同源策略的限制,因此可以用于跨域通信。前端和服务器之间建立 WebSocket 连接后,可以进行实时双向数据传输,适用于实时应用场景。
3.5.1 示例代码
前端代码:
1 | const socket = new WebSocket('ws://wyxup.top'); |
服务器端代码(Node.js):
1 | const WebSocket = require('ws'); |