一、前言
前后端分离的开发模式下,跨域问题总是很常见的。
二、浏览器同源策略
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说 Web 是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
它的核心就在于它认为自任何站点装载的信赖内容是不安全的。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源。
所谓同源是指:域名、协议、端口相同。
三、解决跨域的方式
解决跨域的方式有很多:JSONP、CORS、服务器代理、document.domain、window.name、location.hash、postMessage
四、JSONP 处理跨域
1. JSONP 处理跨域的原理
由于 script 标签不受浏览器同源策略的影响,允许跨域引用资源。因此可以通过动态创建 script 标签,然后利用 src 属性进行跨域,这也就是 JSONP 跨域的基本原理。
2. 优缺点
优点:
3. 示例代码
后端 express
const express = require('express')const app = express()app.get('/', (req, res) => {res.jsonp({code: 0,msg: 'OK'})})app.listen(3000)
前端
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><h1>jsonp</h1><script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script><script>$(function () {$.ajax({url: 'http://localhost:3000',type: 'GET',dataType: 'jsonp',success: function (res) {console.log(res)}})})</script></body></html>
五、CORS (跨域资源共享) 处理跨域
1. 优缺点
优点:
2. 示例代码
后端 express
const express = require('express')const app = express()app.use((req, res, next) => {// 设置响应头res.set({// 控制允许的请求来源'Access-Control-Allow-Origin': '*',// 控制允许的自定义请求头'Access-Control-Allow-Headers': 'abc,efg',// 控制允许的请求方式'Access-Control-Allow-Methods': 'GET,POST,PUT,PATCH,DELETE'})next()})app.get('/', (req, res) => {res.json({code: 0,msg: 'OK'})})app.listen(3000)
前端
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><h1>cors</h1><script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script><script>$(function () {$.ajax({url: 'http://localhost:3000',type: 'GET',success: function (res) {console.log(res)}})})</script></body></html>
六、服务器代理 处理跨域
1. 服务器代理 处理跨域的原理
浏览器有跨域限制,但是服务器不存在跨域问题,所以可以由服务器请求所要域的资源再返回给客户端。
2. 图解

3. 示例代码 - 依赖 http-proxy-middleware
- 目标API接口地址:http://m.maoyan.com/ajax/movieOnInfoList
- 目标服务器:http://m.maoyan.com
- 代理服务器:http://localhost:3000
- Web服务器:http://localhost:8080
代理服务器代码
const express = require('express')const { createProxyMiddleware } = require('http-proxy-middleware');const app = express()app.use((req, res, next) => {// 设置响应头res.set({// 控制允许的请求来源'Access-Control-Allow-Origin': '*',// 控制允许的自定义请求头'Access-Control-Allow-Headers': 'abc,efg',// 控制允许的请求方式'Access-Control-Allow-Methods': 'GET,POST,PUT,PATCH,DELETE'})next()})app.use('/api', createProxyMiddleware({// 目标服务器地址target: 'http://m.maoyan.com',// 虚拟托管站点所需, 一般直接设置为true就好changeOrigin: true,/*** 路径重写** 当我们通过代理访问目标接口的流程大致如下* http://localhost:8080 -> 请求 ->* http://localhost:3000/api/ajax/movieOnInfoList -> 代理到 ->* http://m.maoyan.com/api/ajax/movieOnInfoList* 这时真实的目标接口地址是没有 /api 这个前缀的。所以会导致请求失败 404 等问题** 设置如下的路径重写规则之后,流程如下* http://localhost:8080 -> 请求 ->* http://localhost:3000/api/ajax/movieOnInfoList -> 代理到 ->* http://m.maoyan.com/ajax/movieOnInfoList*/pathRewrite: {'^/api': ''}}))app.listen(3000)
前端
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><h1>服务器代理</h1><script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script><script>$(function () {$.ajax({url: 'http://localhost:3000/api/ajax/movieOnInfoList',type: 'GET',success: function (res) {console.log(res)}})})</script></body></html>
