-
Notifications
You must be signed in to change notification settings - Fork 0
Description
为什么会出现跨域呢?这个是由于浏览器的同源策略。同源策略限制是浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。
同源是从三方面来看:
- 同协议:如都是http或https
- 同域名:如都是
https://a.comm/list和https://a.comm/detail - 同端口:如都是80端口
那如果我想访问不同源的资源,如何做呢?跨域
解决方法
1. JSONP
JSONP有两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。数据就是传入回调函数中的JSON数据。
我们知道script通过src属性可以引入其他域下的JS,如jquery。利用这个特性,我们可以动态创建一个script标签,访问后端地址,拿到数据后插入body中。这种方式需要后端同学配合。
function cb(data) {
console.log('the response data is:' + data);
}
var srcipt = document.createElement('script');
script.src = 'https://example.com/data/?callback=cb';
document.body.insertBefore(script, document.body.firstChild);
// 通过jq
$.getJson('https://example.com/data/?callback=', function(data) {}
// do something
);缺点:
- 安全问题(请求代码总可能存在安全隐患)
- jsonp请求失败难以判断
2. CORS
全称是跨域资源共享,是一种ajax跨域请求资源的方式,支持现代浏览器,IE10以上。基本思想就是使用自定义的http头部让浏览器和服务器进行沟通,从而决定请求或响应式应该成功还是失败。
实现方法简单,使用XMLHttpRequest发送请求时,浏览器发现不符合同源策略时,会在请求头中加上origin。后端进行一系列处理,若确定接受请求则在响应头中加入Access-Control-Allow-Origin,浏览器判断该响应头中是否包含请求头中origin的值,若包含则响应数据,若不包含则驳回。
例如:
请求头:origin: https://example.com/
响应头:Access-Control-Allow-origin: https://example.com/,公共资源也可以是'*'。
这种方式对于前端开发是无感知的,主要是浏览器和后端同学在工作~
3. 图像Ping
就是域服务器金牛星简单、单向的跨域通信的一种方式。请求数据是通过查询字符串的形式发送的,而响应可以是任意内容,但通常是像素图或204响应。通过图像PIng,浏览器得不到任何具体的数据,但通过侦听load和error事件,能知道响应是什么时候接收到的。
var img = new Image();
img.onload = img.onerror = function () {
// do something
};
img.src = 'https://example.com/name=test';通常用于跟踪用户点击页面或动态广告曝光次数。
缺点:
- 只能发送get请求
- 无法访问服务器的响应文本,因此只能用于浏览器和服务器间的单向通信。
4. Web Sockets
是一种新浏览器API,目标是在一个单独的持久链接上提供全双工、双向通信。
在JS中创建了Web Socket之后,会有一个HTTP请求发送到浏览器发起连接。在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为Web Socket协议。因此只有在支持Web Socket协议的浏览器上才能正常工作。
兼容性:Firefox 6+,Safari 5+, Chrome,IOS 4+版Safari。
// http => ws, https => wss
var socket = new WebSocket('https://example.com/server.php');
// 只能发送纯文本数据,对于复杂数据发送前压序列化
socket.send('hello socket');
socket.onmessage = function(event) {
var data = event.data;
};传入WebSocket的URL必须是绝对URL。同源策略对Web Sockets不适用,因此可以通过它打开任意站点的连接。
5. window.postMessage
详细介绍移步MDN
window.postMessage()可以安全地实现跨源通信。只要正确的使用,这种方法就很安全。从广义上讲,一个窗口可以获得对另一个窗口地引用(比如targetWindow = window.opener),然后在窗口上调用targetWinndow.postMessage()方法分发一个MessageEvent消息。接收消息的窗口可以根据需要自由处理事件。传递给window.postMessage()的参数将通过消息事件对象暴露给接收消息的窗口。
otherWindow.postMessage(message, targetOrigin)
-
otherWindow:接受消息的window对象
-
message:将要发送到其他window地数据,会被序列化
-
targetOrigin:接收消息的窗口origin,*表示任意。
window.addEventListener('message', receiveMessage, false);
function receiveMessage(event) {
var origin = event.origin;
if (origin === 'https://example.com:8080') {
var data = event.data;
event.source.postMessage('hi,' + event.origin + data);
}
}通过以上代码,其他window可以监听分发的message。message属性如下:
-
data:从其他window中传递过来的对象。
-
origin:调用postMessage时消息发送方窗口的origin。这个字符串由协议、'://'、域名、':端口号'拼接而成。
-
source:对发送消息的窗口对象的引用,可以使用此来在具有不通origin的两个窗口之间建立双向通信。
6. http-proxy-middleware
基于node.js的插件,如果项目是用vue-cli脚手架搭建的,这个插件是集成在脚手架里的。
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
app.use('/api', createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true }));
app.listen(3000);
vue-cli中修改代理:config/index.js
module.exports = {
dev: {
proxyTable: {
'/api': {
target: url,
changeOrigin: true
}
}
}
}
7. axios和express结合使用
axios
express
const express = require('express');
const axios = require('axios');
app.get(url, (req, res) => {
const url = 'http://www.example.org';
axios.get(url, {
params: req.query
}).then(res => {
console.log(res);
});
});
8. 使用fetch请求
-
当接收到一个代表错误的HTTP状态码时,从fetch返回的promise不会被标记为reject,即使响应的状态码是404。相反,它会将promise状态标记为resolve(但是会将resolve的返回值的OK属性设置为false),仅当网络故障时或请求被阻止时,才会被标记为reject。
-
不会接受跨域cookies。也不能使用fetch()建立起跨域会话。
-
不会发送cookies。除非你设置了credentials:include。默认是same-origin。
fetch('http://example.com/movies.json', {
mode: 'cors'
})
.then(function(response) {
if (response.ok) {
return response.json();
}
throw new Error('network response was not ok');
})
.then(function(myJson) {
console.log(myJson);
});
我的总结就到这里了,在查阅资料的时候也看到几篇不错的总结,可以移步~