跨域
2021-05-20 本文已影响0人
my木子
跨域
-
广义跨域
是指一个域下的文档或脚本试图去请求另一个域下的资源- 资源跳转:
a
链接、重定向、表单提交 - 资源嵌入:
link
、script
、img
、frame
等DOM 标签
,还有样式中background:url()
、@font-face()
等文件外链 - 脚本请求: JS发起的
ajax 请求
、dom
和JS对象
的跨域操作等
- 资源跳转:
- 我们通常所说的跨域是
狭义跨域
,是由浏览器同源策略限制的一类请求场景
同源策略
- 同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到
XSS
、CSFR
等攻击 - 同源是指
协议
+域名
+端口
三者必须相同 - 同源策略限制行为,
Cookie
、LocalStorage
和IndexDB
无法读取;DOM
和JS对象
无法获得;ajax 请求
无法发送
跨域场景
- 同一域名,不同文件或路径,允许跨域
http://www.api.com/a.js
、http://www.api.com/b.js
、http://www.api.com/lab/c.js
- 同一域名,不同端口,不允许跨域
http://www.api.com:8000/a.js
、http://www.baidu.com:8080/b.js
- 同一域名,不同协议,不允许跨域
http://www.api.com/a.js
、https://www.baidu.com/b.js
- 域名和域名对应相同ip,不允许跨域
http://www.api.com/a.js
、http://192.168.4.12/b.js
- 主域相同,子域不同,不允许跨域
http://www.api.com/a.js
、http://x.api.com/b.js
、http://api.com/c.js
- 不同域名,不允许跨域
http://www.api1.com/a.js
、http://www.api2.com/b.js
跨域解决方案
- 通过
jsonp
跨域,但只能只能实现get
一种请求
// 原生实现
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.api.com:8080/list?type=1&callback=handleCallback';
document.head.appendChild(script);
// 回调执行函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
// jquery
$.ajax({
url: 'http://www.api.com:8080/list',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleCallback", // 自定义回调函数名
data: {}
});
// vue.js
this.$http.jsonp('http://www.api.com:8080/list', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
- Vue proxy 代理(nodejs 中间件代理跨域)
/// webpack.config.js
module.exports = {
entry: {},
module: {},
...
devServer: {
historyApiFallback: true,
proxy: [{
context: '/list',
target: 'http://www.api2.com:8080', // 代理跨域目标接口
changeOrigin: true,
secure: false, // 当代理某些https服务报错时用
cookieDomainRewrite: 'www.api1.com' // 可以为false,表示不修改
}],
noInfo: true
}
}
- 跨域资源共享(CORS)
普通跨域请求,只服务端设置Access-Control-Allow-Origin
即可,前端无须设置,若要带cookie
请求,前后端都需要设置
由于同源策略的限制,所读取的cookie
为跨域请求接口所在域的cookie
,而非当前页。如果想实现当前页cookie的写入,可通过NodeJs中间件代理
中cookieDomainRewrite
参数的设置
// 原生 ajax
xhr.withCredentials = true;
// IE8/9需用window.XDomainRequest兼容
// jQuery ajax
$.ajax({
...
xhrFields: {
withCredentials: true // 前端设置是否带cookie
},
crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
...
});
// Vue axios
axios.defaults.withCredentials = true
// Vue vue-resource
Vue.http.options.credentials = true
- document.domain + iframe跨域
- location.hash + iframe
- window.name + iframe跨域
- postMessage跨域
- nginx代理跨域
- WebSocket协议跨域