跳到主要内容

JSONP 跨域方案

<script>标签引入js文件不受跨域影响。不仅如此,带src属性的标签都不受同源策略的影响。

正是基于这个特性,我们通过script标签的src属性加载资源,数据放在src属性指向的服务器上,使用json格式。 由于我们无法判断script的src的加载状态,并不知道数据有没有获取完成,所以事先会定义好处理函数。服务端会在数据开头加上这个函数名,等全部加载完毕,便会调用我们事先定义好的函数,这时函数的实参传入的就是后端返回的数据了。

JSONP 跨域方案 只能发送get请求,不支持postputdelete ,并且不安全,由于是服务端返回了一段JavaScript脚本,容易引起 xss 攻击

原理


前端: 定义callback函数,通过<script></script> 发送请求

<!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.0">
<title>实现 JSONP</title>
</head>
<body>
<script>
function callback(result){
console.log("JSONP 回调函数",result);
}
</script>
<script src="http://localhost:3000/jsonp?name=abc&age=23&callback=callback"></script>
</body>
</html>

服务端: 服务端返回响应类型为text/javascript类型的callback()即可

const Koa = require("koa");
const Router = require("koa-router");

const app = new Koa();
const router = new Router({ prefix: "/" });

router.get("jsonp", async (ctx) => {
const { callback,...params } = ctx.request.query;
const { name, age} = params;
console.log("传入的参数为:",name,age);
const data = {
code: 200,
msg: "JSONP 请求成功!",
data: {},
};
ctx.type = "text/javascript";
ctx.body = `${callback}(${JSON.stringify(data)})`;
});

app.use(router.routes());
app.listen(3000, () => {
console.log("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.0" />
<title>实现 JSONP</title>
</head>
<body>
<script>
function jsonp({ url, params, callback }) {
return new Promise((resolve, reject) => {
const generateURL = () => {
let paramsStr = "";
for (let key in params) {
paramsStr += `${key}=${params[key]}&`;
}
paramsStr += `callback=${callback}`;
return `${url}?${paramsStr}`;
};
callback =
callback ||
`callback${Math.floor(Math.random() * (10 - 0 + 1)) + 0}`;
const script = document.createElement("script");
script.src = generateURL();
document.body.append(script);
window[callback] = function (data) {
resolve(data);
delete window[callback];
document.body.remove(script);
};
});
}

jsonp({
url: "http://localhost:3000/jsonp",
params: {
name: "abc",
age: 23,
},
}).then((result) => {
console.log(result);
});
</script>
</body>
</html>

服务端

const Koa = require("koa");
const Router = require("koa-router");

const app = new Koa();
const router = new Router({ prefix: "/" });

router.get("jsonp", async (ctx) => {
const { callback,...params } = ctx.request.query;
const { name, age} = params;
console.log("传入的参数为:",name,age);
const data = {
code: 200,
msg: "JSONP 请求成功!",
data: {},
};
ctx.type = "text/javascript";
ctx.body = `${callback}(${JSON.stringify(data)})`;
});

app.use(router.routes());
app.listen(3000, () => {
console.log("jsonp 服务启动成功!");
});