Appearance
跨域
跨域解决方案:
- jsonp (常用)
- cors (常用)
- window.name
- document.domain (特定场景)
- postMessage (H5)
- webpack proxy (webScoket) (常用)
- ngix 反向代理 ...
什么是跨域?
拿当前 HTML 页面的地址和在页面中 AJAX 请求的 API 地址做比较: 如果两个地址的协议域名端口号都相同,相当于 HTML 页面从同一个源下根据某个地址获取数据,属于“同源策略请求”,基于 AJAX 是可以直接请求到数据的! 如果三者(协议域名端口号)只要有一个不一样,那么就是“非同源策略请求(跨域请求)”,使用 AJAX 不能直接获取数据了!
HTML 页面的地址:http://localhost:8000/A.html
AJAX 请求的地址:http://localhost:8000/queryInfo
HTML 页面地址:http://localhost:63342/201802LESSON/%E5%85%AC%E5%BC%80%E8%AF%BE/%E8%B7%A8%E5%9F%9F/static/A.html
AJAX 请求接口地址:http://localhost:8000/queryInfo
【报错】
Failed to load
http://localhost:8000/queryInfo
: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin'http://localhost:63342'
is therefore not allowed access.
跨域的普遍性?
现在的项目一般都是前后端分离的,大部分公司都会把后台的程序用一个新的服务管理,把客户端程序也用一个新的服务管理,两个服务不是同一个源;这样就导致客户端是向其他源发送 AJAX 请求,跨域成为请求的阻碍问题;
同源:把客户端程序和服务器程序在一个服务中发布!
=======================================
方案一:JSONP
在客户端 AJAX 不允许直接的跨域请求,但是很多东西都可以直接的跨域,例如:script、link、img、iframe 等(这些标签的 SRC 或者 HREF 设置任何一个资源请求地址,哪怕是其它源下的,也都没有跨域的限制,直接可以把内容获取到 【除非服务器做特殊处理了】 =>针对这个特点,真实项目中某些 JS 文件加载的都是 CDN 地址)
方案二:CORS 跨域资源共享
主要是服务器设置:配置允许跨域的相关头部信息
javascript
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "http://localhost:8000");
res.header("Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Authorization, Accept,X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,HEAD,OPTIONS");
if (req.method === 'OPTIONS') {
res.send('OK!');
return;
}
next();
});
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
客户端
javascript
axios.defaults.withCredentials = true;
//=>xhr.withCredentials=true
axios在某些特定场景下,在发送真实请求之前都会发送一个预请求(OPTIONS)格式的,来验证是否允许跨域
1
2
3
4
2
3
4
弊端:只能指定一个允许源(不能用通配符和指定多个源),所以目前真实项目中基于 CORS 实现跨域资源共享是主流方案
方案三:WEBPACK 代理(webpack proxy)
1. 安装 webpack-dev-server
2. 配置代理:
proxy: {
'/api': {
target: 'https://other-server.example.com',
changeOrigin: true,
secure: false,
pathRewrite: {
'^/api' : ''
}
},
'/getInfo':{
target: 'https://other-server.example.com',
changeOrigin: true
}
}
在 CREATE-REACT-APP 脚手架中,我们只需要在 package.json 中设置 porxy 代理属性,属性值是目标服务器的地址;在客户端发送请求的时候,请求的接口先保证是同源,如果当前源下没有这个接口,没关系,基于 dev-server 使用 webscoket 已经把目标代理服务器上的对应接口数据获取到了,所以直接请求同源下没有的接口,也可以获取数据!
方案四:ngnix 反向代理
方案五:node 作为中间件代理
===============
基于 IFRAME 实现跨域
iframe 可以实现父页面嵌入子页面(父页面中可以基于 js 获取子页面中的内容)
window.name name 是 window 天生自带的属性,而且有一个特点,同源下,早 X 页面中设置 name 的值,页面关掉或者刷新,上次设置的值不消失,能够一直存储最后一次修改的值信息
postMessage