前端基础:如何解决跨域问题
同源策略
同源策略是跨域问题的根本所在。
同源的“源”代表 origin
,同源就表示两个 URL 的 origin
是相同的,origin
由 protocol
、host
和 port
组成。
{ "protocol": "http:", "host": "web.example.com", "port": "", "origin": "http://web.example.com" } 复制代码
同源策略是一个非常重要的安全策略,它用于限制两个源之间在浏览器上进行资源交互。如果缺少了同源策略,网站或服务器很容易受到 XSS、CSFR 等攻击。
方案一(最直接):设置 CORS 跨域资源共享
设置 CORS 是最直接的方法。该方案无需前端操作,只需后端在返回响应时设置响应头即可:
{ "Access-Control-Allow-Origin": "http://web.domain.com" // 指定允许访问的域名 || 通配符 * 表示所有网站都可以访问资源 } 复制代码
方案二(最兼容):使用 Nginx 反向代理
同源策略是浏览器需要遵循的标准,而服务器之间的交互无需遵循同源策略。
使用 Nginx 作为 Web 服务器,监听并接收来自外部(其他服务器)请求,将接收到的请求使用和本机相同的域名转发到后端,然后再将响应返回给前端。
使用 Nginx 反向代理的必要设置如下:
// nginx.conf server { listen 80; server_name web.domain.com; location / { proxy_pass server.domain.com; } } 复制代码
修改后需要重启 Nginx 服务器:
sudo nginx -s reload 复制代码
方案三(最方便):前端使用 Webpack 代理
同样也是利用服务器向服务器请求无需遵循同源策略的特点。只不过这里我们使用 Webpack 作为代理服务器。
该方案无需后端操作,只需在 webpack.config.js
中配置即可:
// webpack.config.js module.exports = { devServer: { proxy: { // 接口前缀 "/api": { target: "http://server.domain.com", // 指定服务器地址 }, }, }, } 复制代码
方案四(最古老):使用 JSONP
JSONP(JSON with Padding)主要是利用 <script>
标签加载脚本不受同源策略的限制这一特性,来加载需要请求的资源。
该方法需要后端和前端同时设置,且仅支持 GET 请求。
后端代码示例(以 node.js 为例):
const querystring = require("querystring") const http = require("http") const server = http.createServer() server.on("request", function (req, res) { const params = qs.parse(req.url.split("?")[1]) const fn = params.callback res.writeHead(200, { "Content-Type": "text/javascript" }) // 设置返回的 MIME 类型为 text/javascript res.write(fn + "(" + JSON.stringify(params) + ")") // 回调函数 res.end() }) server.listen("8080") 复制代码
前端代码示例:
let script = document.createElement("script") // 在 URL 后指定一个回调函数 script.src = "http://server.domain.com/api/list?callback=handleCallback" document.head.appendChild(script) // 回调执行函数 function handleCallback(res) { console.log(res) } 复制代码
方案五(最新):使用 WebSocket
HTML5 定义了 Websocket 协议,该协议主要用于服务器和浏览器之间的持久化连接,并且没有同源策略的限制。
该方案需要后端提供 Websocket 接口,前端进行接收。
前端代码示例:
let ws = new WebSocket("ws://server.domain.com/api/list") ws.onopen = function () { console.log("连接成功") } ws.onmessage = function (res) { console.log(res.data) } ws.onclose = function () { console.log("连接关闭") } 复制代码
后端代码示例(以 node.js 为例):
const WebSocket = require("ws") const server = new WebSocket.Server({ port: 8080 }) server.on("connection", function (socket) { socket.on("message", function (data) { socket.send(data) }) }) 复制代码
如果仅仅是为了实现跨域,不推荐使用 Websocket。
作者:李麦麦
链接:https://juejin.cn/post/7034789106387255333