-
Notifications
You must be signed in to change notification settings - Fork 456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
跨域的方法有哪些?原理是什么? #21
Comments
知其然知其所以然,在说跨域方法之前,我们先了解下什么叫跨域,浏览器有同源策略,只有当“协议”、“域名”、“端口号”都相同时,才能称之为是同源,其中有一个不同,即是跨域。 那么同源策略的作用是什么呢?同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。 那么我们又为什么需要跨域呢?一是前端和服务器分开部署,接口请求需要跨域,二是我们可能会加载其它网站的页面作为iframe内嵌。
尽管浏览器有同源策略,但是 实现原理: Step1: 创建 callback 方法 Step2: 插入 script 标签 Step3: 后台接受到请求,解析前端传过去的 callback 方法,返回该方法的调用,并且数据作为参数传入该方法 Step4: 前端执行服务端返回的方法调用 下面代码仅为说明 jsonp 原理,项目中请使用成熟的库。分别看一下前端和服务端的简单实现: //前端代码
function jsonp({url, params, cb}) {
return new Promise((resolve, reject) => {
//创建script标签
let script = document.createElement('script');
//将回调函数挂在 window 上
window[cb] = function(data) {
resolve(data);
//代码执行后,删除插入的script标签
document.body.removeChild(script);
}
//回调函数加在请求地址上
params = {...params, cb} //wb=b&cb=show
let arrs = [];
for(let key in params) {
arrs.push(`${key}=${params[key]}`);
}
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
});
}
//使用
function sayHi(data) {
console.log(data);
}
jsonp({
url: 'http://localhost:3000/say',
params: {
//code
},
cb: 'sayHi'
}).then(data => {
console.log(data);
}); //express启动一个后台服务
let express = require('express');
let app = express();
app.get('/say', (req, res) => {
let {cb} = req.query; //获取传来的callback函数名,cb是key
res.send(`${cb}('Hello!')`);
});
app.listen(3000); 从今天起,jsonp的原理就要了然于心啦~
jsonp 只能支持 get 请求,cors 可以支持多种请求。cors 并不需要前端做什么工作。
只要服务器设置的Access-Control-Allow-Origin Header和请求来源匹配,浏览器就允许跨域
//简单跨域请求
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', 'XXXX');
});
不满于简单跨域请求的,即是带预检的跨域请求。服务端需要设置 Access-Control-Allow-Origin (允许跨域资源请求的域) 、 Access-Control-Allow-Methods (允许的请求方法) 和 Access-Control-Allow-Headers (允许的请求头) app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', 'XXX');
res.setHeader('Access-Control-Allow-Headers', 'XXX'); //允许返回的头
res.setHeader('Access-Control-Allow-Methods', 'XXX');//允许使用put方法请求接口
res.setHeader('Access-Control-Max-Age', 6); //预检的存活时间
if(req.method === "OPTIONS") {
res.end(); //如果method是OPTIONS,不做处理
}
}); 更多CORS的知识可以访问: HTTP访问控制(CORS)
使用nginx反向代理实现跨域,只需要修改nginx的配置即可解决跨域问题。 A网站向B网站请求某个接口时,向B网站发送一个请求,nginx根据配置文件接收这个请求,代替A网站向B网站来请求。 例如nginx的端口号为 8090,需要请求的服务器端口号为 3000。(localhost:8090 请求 localhost:3000/say) nginx配置如下:
Websocket 是 HTML5 的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。 Websocket 不受同源策略影响,只要服务器端支持,无需任何配置就支持跨域。 前端页面在 8080 的端口。 let socket = new WebSocket('ws://localhost:3000'); //协议是ws
socket.onopen = function() {
socket.send('Hi,你好');
}
socket.onmessage = function(e) {
console.log(e.data)
} 服务端 3000端口。可以看出websocket无需做跨域配置。 let WebSocket = require('ws');
let wss = new WebSocket.Server({port: 3000});
wss.on('connection', function(ws) {
ws.on('message', function(data) {
console.log(data); //接受到页面发来的消息'Hi,你好'
ws.send('Hi'); //向页面发送消息
});
});
postMessage 通过用作前端页面之前的跨域,如父页面与iframe页面的跨域。window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。 话说工作中两个页面之前需要通信的情况并不多,我本人工作中,仅使用过两次,一次是H5页面中发送postMessage信息,ReactNative的webview中接收此此消息,并作出相应处理。另一次是可轮播的页面,某个轮播页使用的是iframe页面,为了解决滑动的事件冲突,iframe页面中去监听手势,发送消息告诉父页面是否左滑和右滑。
父页面 window.addEventListener('message', (e) => {
this.props.movePage(e.data);
}, false); 子页面(iframe): if(/*左滑*/) {
window.parent && window.parent.postMessage(-1, '*')
}else if(/*右滑*/){
window.parent && window.parent.postMessage(1, '*')
}
父页面: let iframe = document.querySelector('#iframe');
iframe.onload = function() {
iframe.contentWindow.postMessage('hello', 'http://localhost:3002');
} 子页面: window.addEventListener('message', function(e) {
console.log(e.data);
e.source.postMessage('Hi', e.origin); //回消息
});
node 中间件的跨域原理和nginx代理跨域,同源策略是浏览器的限制,服务端没有同源策略。 node中间件实现跨域的原理如下: 1.接受客户端请求 2.将请求 转发给服务器。 3.拿到服务器 响应 数据。 4.将 响应 转发给客户端。
以下三种跨域方式很少用,如有兴趣,可自行查阅相关资料。
|
No description provided.
The text was updated successfully, but these errors were encountered: