一、前言
前后端分离的开发模式下,跨域问题总是很常见的。
二、浏览器同源策略
同源策略(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>