特别想说祸从口出,谨言慎行还是老祖宗的智慧啊,本来能过一个不用加班的周五晚上,就因为一句话得加班做一个有关JSOP的demo,内心的悲伤就像上线前的bug,一泻千里。。。
跨域
- 同源策略
协议、域名、端口号 三者完全一致视为同域,否则为跨域。
2.浏览器为什么不支持跨域
cookie LocalStorage ... 不支持跨域
DOM元素也有同源策略(iframe)
ajax 也不支持跨域
jsonp
- 原理
Ajax直接请求普通文件存在跨域无权限访问的问题,不管你是静态页面、动态网页、web服务。。。只要是跨域请求。但是我们又发现Web页面上利用<script>标签调用js文件时则不受跨域的影响。所以,我们在想,emmmm....能不能把我们的跨域请求放在<script>标签里呢? - 实践
- 对于jsonp的封装
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1,user-scalable=no,viewport-fit=cover">
<title>JSONP DEMO</title>
</head>
<body>
<div id="response"></div>
<script>
function jsonp({url, params, cb}) {
return new Promise((resolve, reject) => {
let script = document.createElement('script');
window[cb] = function (data) {
resolve(data);
document.body.removeChild(script);
}
params = {...params, cb};
let arrs = [];
for(let key in params){
arrs.push(`${key}=${params[key]}`);
}
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
})
}
jsonp({
url: 'http://localhost:3000/say',
params: {wd: 'hello jsonp !!!'},
cb: 'show'
}).then(data => {
document.getElementById('response').innerHTML = data;
console.log(data)
})
</script>
</body>
</html>
2.对于服务端的封装(利用node)
2.1 npm install express
2.2 server.js服务端的代码
//server.js 服务端
let express = require('express');
let app = express();
app.get('/say', (req, res) => {
let {wd, cb} = req.query;
console.log(wd);
res.end(`${cb}('HELLO JSONP !!! ')`)
})
app.listen(3000);
2.3 启动服务,在浏览器打开http://localhost:3000/
3.运行


总结
jsonp就是利用< script >标签不会产生跨域的问题来发送跨域请求的;
优点:简单、方便
缺点:1.只能发送get请求; 2.不够安全。
实现方法二
export const getJsonp = (options, getJsonpCallback) => {
let callbackID = `jsonp_${Date.now()}_${Math.ceil(Math.random() * 100000)}`; // 随机生成callbackID
let container = document.getElementsByTagName('head')[0];
let scriptNode = document.createElement('script');
let data = options.data || {};
let url = options.url;
let params = [];
data.callback = callbackID; // 加上callback参数,服务端接口数据根据callback返回函数
for (let key in data) { // 遍历参数,把参数组成数组[name=zhangsan,age:18]
params.push(key + '=' + data[key]);
}
url += (/\?/.test(url)) ? '&' : '?'; // 判断原url是否已经有‘?’,如有给url拼接‘&’,则拼接‘?’
url += params.join('&');
// url拼接参数最终变成www.baidu.com/?name=zhangsan&age=18&callback=jsonp_1526006949894_87849
scriptNode.id = callbackID; // 设置script节点id以便后面删除
scriptNode.src = url;
window[callbackID] = function (response) {
// 定义全局函数,注意函数名是callbackID是跟上面定义的参数data["callback"]=callbackID是一致的
// 服务端接口是根据客户端传的callback而返回callbackID({"code":0,"error":"操作成功","data":{}})
getJsonpCallback(response);
// 当客服端请求接口时即调用了函数callbackID({"code":0,"error":"操作成功","data":{}}),刚好是这里我们定义
// 的全局函数,于是就拿到了数据response
let script = document.getElementById(callbackID);
container.removeChild(script); // 通过script节点id删除script节点
};
scriptNode.type = 'text/javascript';
container.appendChild(scriptNode);
};
网友评论