跨域问题的相关整理
跨域问题的相关整理
一、什么是跨域?
跨域是指一个域下的文档或者脚本试图去请求另一个域下的资源。
(一)广义下的跨域
- 资源跳转:A链接、重定向、表单提交
- 资源嵌入:
<link>
、<script>
、<img>
等dom标签,样式中background:url()
、@font-face()
等文件外链 - 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等
(二)狭义下的跨域
狭义下的跨域,是指浏览器不能执行其他网站的脚本。这是浏览器的同源策略限制造成的,是浏览器保证网站安全的一种手段。只有与当前网页同源的javaScript脚本才能执行。
(三)同源策略
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。查看同源策略-MDN
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源的定义
与 URL http://www.domain.com/a.js
的源进行对比的示例
URL | 说明 | 通信 |
---|---|---|
http://www.domain.com/lab/c.js |
同一域名,不同文件或路径 | 允许 |
http://www.domain.com:8000/a.js |
不同端口 | 不允许 |
https://www.domain.com/b.js |
不同协议 | 不允许 |
http://192.168.4.12/b.js |
域名与ip地址 | 不允许 |
http://x.domain.com/b.js |
主域相同,子域不同 | 不允许 |
http://www.domain2.com/b.js |
不同域名 | 不允许 |
同源策略限制的几种行为
-
Cookie、LocalStorage 和 IndexedDB 无法读取
访问存储在浏览器中的数据,如 localStorage 和 IndexedDB,是以源进行分割。每个源都拥有自己单独的存储空间,一个源中的 JavaScript 脚本不能对属于其它源的数据进行读写操作
Cookies 使用不同的源定义方式。一个页面可以为本域和其父域设置 cookie
-
DOM 和 Js对象无法获得
-
AJAX 请求不能发送
缺少同源策略的危险场景
二、跨域解决方案
(一)JSONP
JSONP的原理——利用script标签获取资源不受到同源策略的限制,我们可以动态创建 script
标签,再请求一个带参网址实现跨域通信。JSONP请求需要服务器支持
jsonp缺点:只能实现get一种请求。
下面使用一个实例,来描述利用script标签,我们怎么获取在不同源服务器下数据的
前端代码
var script = document.createElement("script");
script.type = "text/javascript";
// 传参并指定回调执行函数为jsonpCallback
script.src = "http://localhost:3000?callback=jsonpCallback";
document.head.appendChild(script);
//回调函数
function jsonpCallback(data) {
console.log(data);
}
后端代码
const express = require('express')
const app = express()
app.get('/', (req,res) => {
let callback = req.query.callback
res.send(`${callback}(${JSON.stringify({
success:0,
data:{
name:"xxx"
}
})})`)
})
app.listen(3000, () => { console.log('开启3000端口') })
- 服务端返回时执行定义的回调函数,并将请求回来的数据传入
jquery ajax
$.ajax({
url: 'http://www.domain2.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "jsonpCallback", // 自定义回调函数名
data: {}
});
(二)跨域资源共享(CORS)
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。CORS-MDN
- 客户端(发送ajax和fetch请求)
- 服务端设置相关的头信息
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
// * 不允许携带cooike | 具体地址 只支持单源
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
//预检请求
if (req.method == 'OPTIONS') {
res.send(200); //在正常的请求之前,会发送一个验证,是否可以请求。
}
else {
next();
}
});
具体细节参看阮一峰的文档介绍
(三)node中间件代理
跨域原理: 同源策略是浏览器的安全策略,不是HTTP协议的一部分。如果是服务器向服务器请求就无需遵循同源策略
Vue项目——利用node + webpack + webpack-dev-server代理接口跨域
devServer: {
open: false, // 编译完成是否打开网页
host: "0.0.0.0", // 指定使用地址,默认localhost,0.0.0.0代表可以被外界访问
port: 8080, // 访问端口
https: false, // 编译失败时刷新页面
hot: true, // 开启热加载
hotOnly: false,
proxy: null, // 设置代理
proxy: {
///api开头的接口,代理访问规则
"/api": {
target: "http://123.207.32.32:8000/api/m3", //代理的域名
changeOrigin: true, //是否启用代理
pathRewrite: { //重写请求
"^/api": ""
}
}
},
}
参考文章
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://segmentfault.com/a/1190000015597029#item-3-3