赞
踩
目录
代码地址 git clone https://gitee.com/childe-jia/cross-domain-test.git
同源策略是浏览器为确保资源安全,而遵循的一种策略,该策略对访问资源进行了一些限制。
W3C 上对同源策略的说明:Same origin policy。
1源的组成部分
2下面表格中,只有最后一行的两个源是同源。
源 1 | 源 2 | 是否同源 |
http://www.xyz.com/home | https://www.xyz.com/home | ⛔非同源️ |
http://www.xyz.com/home | http://mail.xyz.com/home | ⛔非同源 |
http://www.xyz.com:8080/home | http://www.xyz.com:8090/home | ⛔非同源 |
http://www.xyz.com:8080/home | http://www.xyz.com:8080/search | ✅同 源︎ |
3同源请求
4非同源请求
5总结:『所处源』与『目标源』不一致,就是『非同源』,又称『异源』或『跨域』
例如有两个源:『源A』和『源B』,它们是『非同源』的,那么浏览器会有如下限制:
『源A』的脚本不能访问『源B』的 DOM。
- <!-- <iframe id="framePage" src="./demo.html"></iframe> -->
- <iframe id="framePage" src="https://www.baidu.com"></iframe>
-
- <script type="text/javascript" >
- function showDOM(){
- const framePage = document.getElementById('framePage')
- console.log(framePage.contentWindow.document) //同源的可以获取,非同源的无法获取
- }
- </script>
『源A』不能访问『源B』的 cookie
- <iframe id="baidu" src="http://www.baidu.com" width="500" height="300"></iframe>
-
- <script type="text/javascript" >
- // 访问的是当前源的cookie,并不是baidu的cookie
- console.log(document.cookie)
- </script>
『源A』可以给『源B』发请求,但是无法获取『源B』响应的数据。
- const url = 'https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc'
- let result = await fetch(url)
- let data = await result.json();
- console.log(data)
备注:在上述限制中,浏览器对 Ajax 获取数据的限制是影响最大的一个,且实际开发中经常遇到。
CORS 全称:Cross-Origin Resource Sharing(跨域资源共享),是用于控制浏览器校验跨域请求的一套规范,服务器依照 CORS 规范,添加特定响应头来控制浏览器校验,大致规则如下:
●服务器明确表示拒绝跨域请求,或没有表示,则浏览器校验不通过。
●服务器明确表示允许跨域请求,则浏览器校验通过。
备注说明:使用 CORS 解决跨域是最正统的方式,且要求服务器是“自己人”。
整体思路:服务器在给出响应时,通过添加Access-Control-Allow-Origin响应头,来明确表达允许某个源发起跨域请求,随后浏览器在校验时,直接通过。
服务端核心代码(以express框架为例):
- // 处理跨域中间件
- function corsMiddleWare(req,res,next){
- // 允许 http://127.0.0.1:5500 这个源发起跨域请求
- // res.setHeader('Access-Control-Allow-Origin','http://127.0.0.1:5500')
-
- // 允许所有源发起跨域请求
- res.setHeader('Access-Control-Allow-Origin','*')
- next()
- }
-
- // 配置路由并使用中间件
- app.get('/',corsMiddleWare,(req,res)=>{
- res.send('hello!')
- })
CORS 会把请求分为两类,分别是:① 简单请求、② 复杂请求。
简单请求 | 复杂请求 |
✅请求方法(method)为:GET、HEAD、POST | 1不是简单请求,就是复杂请求。 |
✅请求头字段要符合《CORS 安全规范》 | |
✅请求头的Content-Type的值只能是以下三种: |
关于预检请求:
请求头 | 含义 |
Origin | 发起请求的源 |
Access-Control-Request-Method | 实际请求的 HTTP 方法 |
Access-Control-Request-Headers | 实际请求中使用的自定义头(如果有的话) |
1第一步:服务器先通过浏览器的预检请求,服务器需要返回如下响应头:
响应头 | 含义 |
Access-Control-Allow-Origin | 允许的源 |
Access-Control-Allow-Methods | 允许的方法 |
Access-Control-Allow-Headers | 允许的自定义头 |
Access-Control-Max-Age | 预检请求的结果缓存时间(可选) |
2第二步:处理实际的跨域请求(与处理简单请求跨域的方式相同)
服务端核心代码:
- // 处理预检请求
- app.options('/students', (req, res) => {
- // 设置允许的跨域请求源
- res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
- // 设置允许的请求方法
- res.setHeader('Access-Control-Allow-Methods', 'GET')
- // 设置允许的请求头
- res.setHeader('Access-Control-Allow-Headers', 'school')
- // 设置预检请求的缓存时间(可选)
- res.setHeader('Access-Control-Max-Age', 7200)
- // 发送响应
- res.send()
- })
-
- // 处理实际请求
- app.get('/students', (req, res) => {
- // 设置允许的跨域请求源
- res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
- // 随便设置一个自定义响应头
- res.setHeader('abc',123)
- // 设置允许暴露给客户端的响应头
- res.setHeader('Access-Control-Expose-Headers', 'abc')
- // 打印请求日志
- console.log('有人请求/students了')
- // 发送响应数据
- res.send(students)
- })

上述的配置中需要自己配置响应头,或者需要自己手动封装中间件,借助cors库,可以更方便完成配置
●安装cors
npm i cors
●简单配置cors
app.use(cors())
●完整配置cors
- // cors中间件配置
- const corsOptions = {
- origin: 'http://127.0.0.1:5500', // 允许的源
- methods: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS'], // 允许的方法
- allowedHeaders: ['school'], // 允许的自定义头
- exposedHeaders: ['abc'], // 要暴露的响应头
- optionsSuccessStatus: 200 // 预检请求成功的状态码
- };
-
- app.use(cors(corsOptions)); // 使用cors中间件
默认js是不能访问后端设置的响应头的,需要后端暴露
1JSONP 概述: JSONP 是利用了<script>标签可以跨域加载脚本,且不受严格限制的特性,可以说是程序员智慧的结晶,早期一些浏览器不支持 CORS 的时,可以靠 JSONP 解决跨域。
2基本流程:
3图示:
4代码示例:
- <button onclick="getTeachers()">获取数据</button>
-
- <script type="text/javascript" >
- function callback(data){
- console.log(data)
- }
-
- function getTeachers(url){
- // 创建script元素
- const script = document.createElement('script')
- // 指定script的src属性
- script.src= 'http://127.0.0.1:8081/teachers'
- // 将script元素添加到body中触发脚本加载
- document.body.appendChild(script)
- // script标签加载完毕后移除该标签
- script.onload = ()=>{
- script.remove()
- }
- }
- </script>

5jQuery 封装的 jsonp
?callback=?' 为固定格式 会自动解析
- $.getJSON('http://127.0.0.1:8081/teachers?callback=?',(data)=>{
- console.log(data)
- })
服务器之间是没有跨域问题的,要使用express 启动静态资源保证自己的服务器跟页面在同源下
- // 启动静态资源 让服务器跟页面同一个源
- app.use(express.static("./public"));
借助http-proxy-middleware配置代理
- const { createProxyMiddleware } = require('http-proxy-middleware');
-
- app.use('/api',createProxyMiddleware({
- target:'https://www.toutiao.com',
- changeOrigin:true,
- pathRewrite:{
- '^/api':''
- }
优点:
缺点:
使用场景:
整体思路:让nginx充当两个角色,既是 静态内容服务器,又是代理服务器。
修改nginx配置如下,注意nginx的根目录最好不是 C 盘
- # 配置nginx根目录
- location / {
- root D:\dist;
- index index.html index.htm;
- }
-
- # 配置代理
- location /dev/ {
- # 设置代理目标
- proxy_pass http://sph-h5-api.atguigu.cn/;
- }
2修改前端项目,让所有请求都转发给 /dev,随后重新打包
- const request = axios.create({
- baseURL:'/dev',
- timeout:10000
- })
随后直接访问nginx服务器即可,例如 nginx如果运行在8099端口,则访问
http://localhost:8099
随后会遇到刷新404问题,追加nginx配置来解决
-
- # 配置nginx根目录
- location / {
- root D:\dist;
- index index.html index.htm;
- try_files $uri $uri/ /index.html; # 解决刷新404
- }
- # 配置代理
- location /dev/ {
- # 设置代理目标
- proxy_pass http://sph-h5-api.atguigu.cn/;
- }
加上这两个“/”就剔除掉了dev
1. 使用vue.config.js文件配置代理:
在Vue项目的根目录下创建一个vue.config.js文件,并添加以下代码:
- module.exports = {
- devServer: {
- proxy: {
- '/api': {
- target: 'http://api.example.com',
- changeOrigin: true,
- pathRewrite: {
- '^/api': ''
- }
- }
- }
- }
- }
上述代码中,我们使用devServer
配置项来配置代理服务器。其中proxy
属性用于配置代理的规则,/api
表示需要代理的接口路径。target
属性表示代理的目标服务器地址,changeOrigin
属性表示是否改变请求的源地址,pathRewrite
属性用于重写请求的路径。
优点:
缺点:
使用场景:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。