前言
在项目中总会遇到这样的报错:
当我们还是一个新手的时候总会第一时间百度这是什么报错,当我们遇到问题多了,当看到这样的报错第一时间就知道这是跨域问题,
跨域: 一个老生常谈的问题、很长一段时间我都认为这样基础问题没什么好写的了。 但是当我在次找工作的时候,发现很多面试官都爱问道,什么是跨域。由于没有深入的去了解透这个问题。回答得不敬人意。接着这个机会,决定从底层开始弄明白跨域问题,同时记录下来后面好回顾。
很多时候都是第一时间去查询一个问题得解决办法,并不会第一时间去弄清除为啥会引发这个问题
什么是跨域
跨域全称为Cross-Origin Resource Sharing,意为跨域资源共享,是一种允许当前域下进行资源被其他域资源脚本访问得机制。
但是浏览器却不支持这样得跨域请求,因为这违反了浏览器得同源安全策略。
跨域并不是请求没有发送出去,服务器收到请求并且返回数据,只有被浏览器拦截了返回结果
同源安全策略
在了解跨域之前我们先来弄清楚什么是同源安全策略
同源是指协议、域名、端口三者相同
是一种重要得安全策略,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击
只有当 protocol(协议)、domain(域名)、port(端口)三者一致 才是同源。
浏览器的安全同源策略导致得请求跨域报错问题
怎么解决跨域问题
后端配置跨域资源共享:CORS
CORS 全称是 Cross-origin resource sharing 跨域资源共享,CORS 的实现关键在于后端
主要配置 “Access-Control-Allow-Origin”
浏览器是否启用同源安全策略,是根据后台接口 响应的 Access-Control-Allow-Origin 响应头来决定的。
后端配置 Access-Control-Allow-Origin 响应头为开发过程中最常用,也是最直接的方法。
res.header('Access-Control-Allow-Origin', '*')
配置代理
介绍这之前 先说说正向代理与反向代理
正向代理
客户端与原始数据服务之间的代理,客户端发送一个请求个的代理目标,代理目标将请求发送到目标服务。服务器返回结果返回给客户端的过程,只有客户端能够使用正向代理。
反向代理
客户端发送请求,首先到达代理服务,有代理服务将请求发送给目标服务,目标服务响应请求后将结果返回给代理服务,代理服务将结果返回请求客户端的过程。
正向代理 | 反向代理 |
---|---|
代理客户端 | 代理服务端 |
隐藏真实客户端,真实客户端对服务器不可见 | 隐藏真实服务端,真实服务器对客户端不可见 |
解决访问限制问题 | 提供负载均衡,安全保护,数据缓存 |
nginx 反向代理
proxy_pass 主要使用在nginx 代理配置,使用方法灵活多样;
简单代理
server {
listen 80;
listen [::]:80;
listen 443 ssl;
server_name localhost;
location / {
proxy_pass http://127.0.0.10:8080;
}
}
使用 upstream方法代理
upstream test {
server: 192.168.0.13:8989;
}
server {
listen 80;
listen [::]:80;
listen 443 ssl;
server_name localhost;
location / {
proxy_pass http://test;
}
}
在nginx中配置proxy_pass代理转发时,如果在proxy_pass后面的url加/,表示绝对根路径;如果没有/,表示相对路径,把匹配的路径部分也给代理走。
node 中间件正向代理
同源策略只针对浏览器发送出来的请求有用,对应服务的访问服务端不受限制的。
我们可以使用代理服务方式来解决跨域问题,主要有一下几个步骤:
- 接受客户端请求 。
- 将请求转发给服务器。
- 拿到服务器响应数据。
- 将响应转发给客户端。
前端配置代理
vue cli 配置正向代理
vue cli 提供的 webpack-dev-server 开发服务器支持设置代理,可以在 vue.config.js 文件中配置devServer配置项下的proxy配置项,把对/api路径的请求代理转发到真实的后端服务器路径,再根据需要对转发后的URL进行改写。
module.exports = {
devServer: {
port: ‘8090,
open: false,
overlay: {
warnings: false,
errors: true,
},
proxy: {
'/pms': {
target: 'http://192.168.3.11:86',
changeOrigin: true,
pathRewrite: {
'^/zhihuitouzi/qqpt-apply/pms': '/pms',
},
}
},
}
react 配置代理
在项目目录下创建 setupProxy文件, 使用脚手架工具不能找到对应文件。
const proxy = require('http-proxy-middleware');
module.exports = function (app) {
app.use(
proxy('/test/api', {
target: 'http://localhost:8000',
changeOrigin: true, // 默认值是false
pathRewrite: {
'^/api1': '' }
}),
proxy('/demmo/api', {
target: 'http://localhost:5001',
changeOrigin: true, // 默认值是false
pathRewrite: {
'^/api2': '' }
}),
)
}
JSONP
JSONP 的原理是利用 <script> 标签的 src 属性允许跨域加载资源,来与服务器进行数据传输。
但是 JSONP 需要后端配合才能实现最终的跨域请求。
具体的实现流程:
- 声明一个回调函数,其函数名当作参数值传递给跨域请求数据的服务器,函数形参为要获取的目标数据,即服务器返回的data
- 创建一个script标签,把跨域的api数据接口赋值给src属性,通过问号传参的方式加上函数名。比如 ?callback=getDatas
- 服务器接收到请求后,把传递进来的函数名和它需要的数据拼接成一个函数调用形式的字符串
- 最后服务器通过HTTP协议返回给客户端,解析执行函数
该方法只支持get 请求,
常规使用的常见为 一些固定了的第三方接口;在日常开发使用非常少;