JSONP原理
跨域
因为浏览器出于安全考虑,有同源策略。也就是说,如果协议、域名或者端口有一个不同就是跨域,Ajax 请求会失败。
也就是说,没有同源策略的情况下,A 网站可以被任意其他来源的 Ajax 访问到内容。如果你当前 A 网站还存在登录态,那么对方就可以通过 Ajax 获得你的任何信息。当然跨域并不能完全阻止 CSRF。
然后我们来考虑一个问题,请求跨域了,那么请求到底发出去没有? 请求必然是发出去了,但是浏览器拦截了响应。你可能会疑问明明通过表单的方式可以发起跨域请求,为什么 Ajax 就不会。因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。
解决方案有很多,现在说一下jsonp的实现
原理
通俗的说就是利用script标签中的src属性能请求js代码资源的原理,从服务器请求一些js代码来执行。
var express = require('express');
var router = express.Router();
router.get('/',function(req,res,next){
res.send(`JSONP_Practice_By_Joey_Tribiani`)
});
module.exports = router;
上面就是我们一个简单的服务器端的代码,get方式访问’/'路由返回数据,这样我们在客户端利用script标签的src属性请求的时候,得到这个结果,但是这里出现问题了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YahaADKE-1584809454903)(C:\Users\joey\AppData\Roaming\Typora\typora-user-images\image-20200322001952871.png)]
报了语法错误,原因就是script标签请求到js代码后会立即执行,而我们返回的是字符串,js引擎是无法当做js代码执行的,因此我们需要简单优化下,返回的数据我们可以用模板运算符拼接一下
var express = require('express');
var router = express.Router();
router.get('/',function(req,res,next){
res.send(`console.log("JSONP_Practice_By_Joey_Tribiani")`)
});
module.exports = router;
这样子我们就如愿以偿的拿到了想要的结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-35NKUake-1584809454905)(C:\Users\joey\AppData\Roaming\Typora\typora-user-images\image-20200322002252020.png)]
JSONP 使用简单且兼容性不错,但是只限于 get
请求。
在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的,这时候就需要自己封装一个 JSONP,以下是简单实现
function jsonpFn(url,cb){
const createSscript = document.createElement("script");
createSscript.src=`${url}?callback=${cb}`;
createSscript.src=`${url}?callback=${cb}`;
document.body.appendChild(createSscript);
document.querySelector("body>script:last-child").remove();
}
这里注意了,我们是把自己想要调用的函数的函数名传过去,所以传参数cb的时候要传字符串,然后由于我们是以query的方式传递信息,所以服务端需要配合修改
var express = require('express');
var router = express.Router();
router.get('/',function(req,res,next){
const cb = req.query.callback //这里就拿到了我们传的函数名
console.log(cb);
res.send(`${cb}("JSONP_Practice_By_Joey_Tribiani")`)
});
module.exports = router;
这样一个简单的jsonp封装就完成了