一说跨域,一定会先说同源策略,有时间的可以看一下官方解释的同源策略
浏览器的同源策略 - Web 安全 | MDN
同源策略:同源策略是浏览器的一个安全行为,是指浏览器对不同源的脚本或文本的访问方式进行限制。(ajax请求时,浏览器要求当前网页和server必须同源)
那么什么是同源呢?
同源:指两个页面具有相同的协议,域名,端口号
为什么需要同源策略?
浏览器为了保护用户的数据安全,尽可能阻止跨域攻击,浏览器是公共资源,而一个网站是私有资源。假设没有同源策略,A网站的API可以被任意来源的ajax请求访问,包括了用户的隐私信息。会出现很大的问题。
举个栗子:
如果你登录淘宝,淘宝给你返回了一个cookie,下次请求你会带上cookie,这样子服务器就知道你登录过了,假设,你买东西过程中,又点来了一个链接,由于没有同源策略,他就在后台操作向淘宝发起请求,那么就相当于不法网站利用你的账号进行为所欲为了,假设这个账号是个银行账号,你的钱可能已经没有了
同源策略限制的不同源之间的交互,主要是针对js中的XMLHttpRequest请求,有一些情况是不受影响的如:html的一些标签的请求,链接标签A,图片标签Img,script标签,这些标签的请求可以为不同源地址
那同源策略到底限制了哪些行为?
因为浏览器存在了同源策略导致跨域,那什么是跨域,协议,域名(主机号),端口号有一个不同就是跨域
案例:
跨域问题会在各种情况出现,当正常进行访问时,需要解决跨域带来的问题,那跨域有哪些解决方案呢??
//可用于统计打点,统计第三的点击次数
//CDN
jQuery
$.ajax({
url: "http://wwww.ceshi.com/login",
type: 'get',
dataType: 'jsonp',
jsonpCallback: 'callback',
data: {
'username': 'aaa'
}
})
vue.js
下载安装插件
npm install vue-jsonp --save
main.js中引用
import Vue from 'vue'
import VueJsonp from 'vue-jsonp'
Vue.use(VueJsonp)
使用
created(){
this.tosend();
},
mounted(){
window.jsonpCallback = (res) => {
console.log(res)
}
},
methods: {
tosend(){
this.$jsonp('http://wwww.ceshi.com/login',
{ params: { username: 'aaa' },
jsonp: 'jsonpCallback' //这个回调函数才是jsonp返回的数据 })
.then((res) => { console.log(res) })
}
}
浏览器可以通过domain查看当前的文档的服务器域,检查两个网页是否同源,强制设置domain为同一个域,就可以实现同域,利用这个,可以实现两个页面共用cookie,也可以进行数据的传递等
缺点:只适用于两个页面属于同一基础域,且协议和端口号相同
像:aa.qq.com, bb.qq.com,cc.qq.com,他们都有公共的上级域名qq.com
又比如:主域名:www.test.com ,子域名为child.test.com,对于两个页面,同时设置
document.domain = 'test.com'
则就可以各自进行访问window对象了
例如:
www.test.com
childe.test.com
官方解释: window.postMessage - Web API 接口参考 | MDN
postMessgae是h5引入的API,它可以允许不同源的脚本采用异步的方式进行通信,可以实现
缺点:存在一定安全问题
如果您不希望从其他网站接收message,请不要为message事件添加任何事件侦听器。如果您确实希望从其他网站接收message,请始终使用origin和source属性验证发件人的身份。 任何窗口都可以向任何其他窗口发送消息,并且您不能保证未知发件人不会发送恶意消息。
先讲解一下api
发送信息
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow - iframe的contentWindow属性,执行window.open返回的窗口对象,或者是命名过或数值索引的window.frames
message - 发送给其他页面的数据
targetOrigin - 指定哪些窗口可以接受传递的数据,可以是字符串“*”(所有页面可接受)或者是一个url,如果是明确消息发送的窗口,就提供一个确切的url,不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。
**transfer**可选 - 是一串和message 同时传递的
Transferable
对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
接收数据
// 监听 message 消息
window.addEventListener('message', function (e) {
console.log(e.source); // e.source 发送消息的窗口
console.log(e.origin); // e.origin 消息发向的网址
console.log(e.data); // e.data 发送的消息},false);
案例:
www.test.com
www.test2.com
这是一个纯服务器端操作 - 可以看这个部分的最后,服务器端只要设置好了就行了,前端只需要正常请求就ok了
CORS是W3C标准,允许浏览器向跨源服务器发送XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制,并且需要浏览器和服务器同时支持,目前所有的浏览器都支持该功能除了IE,IE浏览器不能低于IE10,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求
CORS官方文档:跨源资源共享(CORS) - HTTP | MDN
阮一峰大神对CORS的详细讲解:跨域资源共享 CORS 详解 - 阮一峰的网络日志
实现的原理是自定义HTTP的头部允许浏览器和服务器互相了解对方,从而去决定请求和响应成功与否
后端设置后,可以在返回中看到
HTTP请求头部字段
Orgin - 表明预检请求或者实际请求的源站,值为源站的url,不包含任何路径信息,只是服务器的名称,就是HTTP请求头,涉及到CORS请求都必需携带
Access-Control-Request-Method - 实际请求所使用的HTTP方法告诉服务器
Access-Control-Request-Headers - 将要发起的跨域请求中包含的请求头字段
服务器在响应字段中来表明是否允许这个跨域请求,浏览器收到后检查如果不符合要求,就拒绝后面的请求
HTTP响应字段
Access-Control-Allow-Origin - 允许哪些域来访问(*表示允许所有域的请求)
Access-Control-Allow-Methods - 允许哪些请求方式
Access-Control-Allow-Headers - 允许哪些请求头字段
Access-Control-Allow-Credentials - 是否允许携带Cookie
对于普通跨域请求 - 只需要服务器端进行设置Access-Control-Allow-Origin就可以了
如果是cookie的跨域请求,就需要前后端都需要设置,后端已经开启CORS,前端需要也携带cookie,此时需要在前端请求头加上withCredentials: true,
原生
function tosend() {
var xhr = new XMLHttpRequest();
//前端是否携带token
xhr.withCredentials = true;
xhr.open("post", "http://wwww.test.com/login", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// 声明请求源
xhr.setRequestHeader("Origin", "http://wwww.test.com");
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var responseText = xhr.responseText;
console.info(responseText);
}
}
}
jQuery
$.ajax({
type: 'post',
crossDomain: true,
url: 'http://wwww.test.com/login',
data: {
UserName: 'aa',
},
dataType:'json',
xhrFields: {
withCredentials: true
},
success: function(data, textStatus, jqXHR){ }
});
vue
vue-resurce
Vue.http.options.credentials = true
axios
axios.defaults.withCredentials = true
后端要怎么开启cors?那是后端的事情了
但是其实只需要后端添加相应的字段就行了
/* * 导入包:import javax.servlet.http.HttpServletResponse;
* 接口参数中定义:HttpServletResponse response
*/
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
nginx代理跨域,需要进行修改配置文件,
nginx实现简单代理_哆来A梦没有口袋的博客-CSDN博客_nginx代理怎么做
直接在配置文件,vue.config.js中,vue的webpack的配置文件,遵循的common.js的规范,nodejs去转发服务
module.exports = {
devServer: {
host: 'localhost',
host: '0.0.0.0',
port: '8081',
before: (app) => {//控制台查看是否成功,正常情况都可以不需要这个函数,只是辅助开发
var url = require('url');
app.use((req, res, next) => {
function fullUrl(req) {
return url.format({
protocol: req.protocol,
host: req.get('host'),
pathname: req.originalUrl
});
}
console.log("req.url", fullUrl(req));
next()
})
},
proxy: { //代理服务器,一般使用mock联调 与 vue-cli2.x的 proxyTable 一样的功能
// '/': {
// target: "http://cqasia.860001.xyz:12091",
// },
"/dima_server/api": {
target: 'https://cqasia.860001.xyz:12092', //代理的地址
pathRewrite: { "^/dima_server/api": "/dima_server/api" }, //路径转发规则
ws: false, //如果是要代理websockets,需要边为true
changeOrigin: true,//是否改变源,告诉服务器端真实地址
},
}
}