一、跨域是什么?
跨域(Cross-Origin)是指在浏览器中,当一个网页的 JavaScript 代码向不同源(即协议、域名、端口号有任何一个不同)的服务器发送 AJAX 请求时,就会发生跨域请求。同源策略(Same-Origin Policy)是浏览器的一种安全机制,它要求 JavaScript 只能访问与当前页面具有相同源的资源。
二、浏览器的同源策略是什么?
浏览器的同源策略(Same-Origin Policy)是一种安全机制,它是浏览器对不同源(即协议、域名、端口号有任何一个不同)之间的 JavaScript 交互进行限制的规则。同源策略要求网页中使用的脚本只能访问与其来源相同的资源,这样可以防止恶意脚本在用户不知情的情况下获取用户的敏感信息或者进行其他恶意操作。
同源策略通常会限制以下行为:
-
Cookie、LocalStorage 和 IndexDB:不同源的页面无法读取或写入彼此的 Cookie、LocalStorage 或 IndexDB。
-
DOM 访问:不同源的页面无法通过 JavaScript 访问彼此的 DOM 元素。
-
AJAX 请求:不同源的页面无法通过 AJAX 发起跨域请求。
-
Frame 和 iframe:不同源的页面无法通过 Frame 或 iframe 将内容嵌入到另一个页面中。
通过同源策略的限制,浏览器可以保护用户的隐私和安全,防止恶意网站对用户数据进行不当访问和操作。开发者在进行跨域请求时,需要遵循同源策略,可以使用 CORS(Cross-Origin Resource Sharing)、JSONP、代理转发等方式来实现跨域通信。
三、解决跨域的方案
常见的跨域解决方案包括:
-
JSONP(JSON with Padding):通过动态创建
<script>
标签,将数据以 JavaScript 函数调用的形式返回,利用<script>
标签的跨域特性来实现跨域请求。但是 JSONP 只支持 GET 请求,且只能传递有限的数据格式。 -
CORS(Cross-Origin Resource Sharing):该机制是通过在服务器响应中设置一些特殊的 HTTP 头部来实现跨域访问控制。服务器端需要设置允许跨域的域名,浏览器在发起跨域请求时会先发送一个 OPTIONS 请求进行预检,如果服务器允许该域名进行跨域访问,就会发送实际的请求。
-
代理转发:将前端应用的请求发送到同域的代理服务器上,再由代理服务器将请求转发给目标服务器。这种方式可以绕过浏览器的同源策略限制。
-
WebSocket:WebSocket 协议本身支持跨域通信,通过 WebSocket 连接可以建立长连接并实时传输数据。
需要注意的是,跨域问题只存在于浏览器端,因为浏览器对同源策略进行了限制,而在服务器端不存在跨域问题。
四、最常用的跨域解决方案 代理转发(前端) 和 cors(后端)
1、代理转发 (这里拿vite配置举例)
// vite.config.ts
// 用于配置开发服务器相关的选项
server: {
host: '0.0.0.0', // 指定开发服务器的主机地址 监听所有可用的网络接口
open: true, // 是否在启动时自动打开浏览器
port: Number(env.VITE_APP_PORT), // 指定开发服务器的端口号
// 用于配置代理服务器,将指定的请求转发到其他服务器上
proxy: {
/**
* env.VITE_APP_BASE_API: /dev-api
*/
[env.VITE_APP_BASE_API]: {
changeOrigin: true,
// // 线上接口地址
// 开发接口地址
target: "http://127.0.0.1:3001",
rewrite: (path) =>
path.replace(new RegExp("^" + env.VITE_APP_BASE_API), ""),
},
},
}
b、结果
未配置代理转发
可以看到未配置代理转发无法获取响应信息
配置代理转化后
可以看到能获取响应信息
关键就是 target: "http://127.0.0.1:3001", 这行代码 用于将前端应用发送的请求代理转发到指定的后端服务地址。
即为:http://localhost:8080/dev-api/auth/captcha 变成了 http://localhost:127.0.0.1:3001/auth/captcha
2、cors 解决跨域(这里拿node.js搭建的服务器举例)
a、下载 cors
npm i cors
b、导入 cors 并 挂载 cors 中间件
// 导入 express
const express = require('express')
// 导入 express-session
const session = require('express-session');s
// 导入 cors
const cors = require('cors')
// 导入路由对象
// 导入上传文件路由对象
const uploadData = require('./router/upload.js')
// 导入认证中心路由方法
const auth = require('./router/auth.js')
// 创建服务器
const app = express()
// 挂载中间件
// 挂载 cors 中间件 (解决跨域)
// 允许所有源
app.use(cors())
// 指定允许跨域的源
// app.use(cors({
// origin: ['https://example1.com', 'https://example2.com']
// }))
// 挂载 express.json() 中间件 (处理json数据)
app.use(express.json())
// 挂载 express.urlencoded({ extended: true }) (处理 url 数据)
app.use(express.urlencoded({ extended: true }))
// 挂载 express.static 中间件 (访问静态资源)
app.use('/image',express.static('asset/images/'));
app.use('/file', express.static('asset/files/'))
// 挂载路由对象
// 上传文件
app.use('/upload',uploadData)
// 认证中心
app.use('/auth', auth)
// 挂载错误中间件
// 启动服务器
app.listen(3001, () => {
console.log('App in running http://127.0.0.1:3001')
})