什么是跨域问题
跨域问题的出现是因为浏览器的同源策略问题,所谓同源:就是两个页面具有相同的协议(protocol),主机(host)和端口号(port),即指协议,端口,域名。只要这个3个中有一个不同就是跨域。它是浏览器最核心也是最基本的功能,如果没有同源策略我们的浏览器将会十分的不安全,随时都可能受到攻击。
当我们请求一个接口的时候,出现如:Access-Control-Allow-Origin 字眼的时候说明请求跨域了
展示跨域问题
前端请求后端8889端口开放的端口
1 | this.$axios({ |
会出现因为跨域,所以请求失败的消息
1 | Access to XMLHttpRequest at 'http://localhost:8889/' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. |
处理跨域
前端
jsonp
1 | // 后端接口 |
Proxy
通过网络代理,通过代理服务与另一个网络终端进行非直接的连接
通过webpack搭建一个本地服务器,作为请求的代理对象,通过该服务器转发请求至目标服务器。
但存在的问题是,如果webpack服务器与web接口服务器不在一起,仍然存在跨域问题。===>由于生产环境基本上后端有后端部署的服务器、前端有前端部署的服务器,因此这个无法在生产上使用
Vue
-
开发阶段: 配置代理
-
如果你是用 Vue CLI 创建的项目,也可以开发阶段,配置一下 webpack 的 devServer,它有自带一个 proxy 代理服务器。
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// Vue3中是在vue.config.js配置
module.exports = {
devServer:{
host: 'localhost',
open: true, // vue项目启动时自动打开浏览器
port: 8080, // 本地服务器使用的端口
proxy: { //配置跨域
'/api': { // `/api`是代理标识,用于告诉node,url前面是`/api`的就是使用代理的
target: 'http://127.0.0.1:5000/', // 目标地址,应该写提供接口的后台服务器的真实地址
changOrigin: true, // 是否跨域
pathRewrite: {
'^/api': '' // 把实际request URL中的`/api`用``来代替
/* 重写路径,当我们在浏览器中看到请求的地址为:http://localhost:8080/api/core/getData/userInfo 时, 实际上访问的地址是:http://121.121.67.254:8185/core/getData/userInfo */
}
},
}
}
}- 后端配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20from flask import Flask
from flask_cors import cross_origin
app = Flask(__name__)
def hello_world():
return 'Hello World!'
def apix():
return 'Hello api!'
def api():
return 'Hello do!'
if __name__ == '__main__':
app.run()- 访问
http://localhost:8080/
时会出现跨域问题,http://localhost:8080/api
时浏览器直接跳转到后端内容 - 网络请求
http://localhost:8080/do
由于do接口允许跨域所以成功拿到数据,/api
成功拿到Hello World实现跨域- 为什么get("/api")拿到的是
http://localhost:8080/
的数据呢?首先拼接成http://localhost:8080/
, 然后符合代理规则,所以根据pathRewrite吧/api
替换成了""
,于是请求变成了访问http://localhost:8080/
。再因为vue.config.vue中target指定了axios的目标url,会把http://localhost:8080
代理掉,所以就代理转向访问了http://localhost:5000/
注: 没有指定axios的baseURL则为本身, 会自动加上http://localhost - 可以测试是不是这个逻辑,axios.get("/do"), 提示
http://localhost:8080/do
不存在, 也不符合代理规则- axios.get("/"), 虽然也不符合代理规则,但其本身
http://localhost:8080/
是有的, 所以也能请求到数据,只不过这个是index.html的数据
- axios.get("/"), 虽然也不符合代理规则,但其本身
- 如果指定axios的baseURL=“http://baidu.com”,则xxx.get("/api")会变成
http://baidu.com/api
- 为什么get("/api")拿到的是
-
-
生产环境: 配置nginx转发
服务器端
根据CORS的定义,是不允许浏览器调用的前端服务主动去拿另一个域下的资源,那么就改变前端服务直接拿的方式,而是通过请求代理服务器数据从而间接请求另一个域下的资源,代理服务器再请求到数据后,再让代理把数据交给前端即实现了跨域的效果。
==》前端服务跟代理服务器是同源的,而nginx对服务端转发的请求不会触发浏览器的同源策略。
nginx
基础使用-简单版
1 | ## 配置反向代理的参数 |
这里是起了一个叫xx_domain的nginx服务器,侦听8080端口(一般是localhost)。 这边写的是xx_domain,则axios中也应该请求这个链接(baseURL设置为http://xx_domain.com)
更多操作
1 | # 如下的是青龙的转发配置 |
后端
修改响应头
根据上述CORS反馈的消息
No 'Access-Control-Allow-Origin' header is present on the requested resource.
来看,是由于没有设置响应头Access-Control-Allow-Origin
,因此其中一个做法是可以修改响应头中的Access-Control-Allow-Origin
1 | app.get("/", function(req, res){ |
还在相应的接口上添加@CrossOrigin
表示允许跨域请求
可以看做是修改响应头的变种
1 |
|
附录
采坑说明:
- CORS是浏览器的限制,而HbuilderX中内置的浏览器是没有跨域问题的,需要打开外部浏览器才能看到。
Author: Mrli
Link: https://nymrli.top/2021/11/26/前端-跨域/
Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.