JSONP 是服务器与客户端跨源通信的常用方法,最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。
它的基本思想是,网页通过添加一个 script 元素,向服务器请求 JSON 数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
缺点:
- 只能发送 get 请求,不支持 post put delete
- 不安全,xss 攻击,因此很多公司现在都不采用
实现步骤
(1)网页动态插入 script 元素,由它向跨源网址发出请求。
function addScriptTag(src) {var script = document.createElement('script');script.setAttribute('type','text/javascript');script.src = src;document.body.appendChild(script);}window.onload = function() {addScriptTag('http://example.com/ip?callback=foo');}function foo(data) {console.log('Your public IP address is:' + data.ip);}
通过动态添加 script 元素,向服务器 example.com 发出请求。
(2)该请求的查询字符串有一个 callback 参数,用来指定回调函数的名字,这对于 JSONP 是必需的。
(3)服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。
foo({"ip": "8.8.8.8"});
由于 script 元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了 foo 函数,该函数就会立即调用。作为参数的 JSON 数据被视为 JavaScript 对象,而不是字符串,因此避免了使用 JSON.parse 的步骤。
封装 JSONP 方法
参数
url:请求地址params:传递给后台的参数cb:回调函数名称
代码
//=> 解构赋值function jsonp({url, params, cb}) {return new Promise((resolve, reject) => {// 手动创建一个 script,插入到 body 后面let script = document.createElement('script');// 创建一个全局 cb 回调函数// 数据请求回来之后,会执行这个函数,触发 resolve,完成使命,移除这个 script 标签// 继而执行 then 中定义的回调函数window[cb] = function (data) {resolve(data);document.body.removeChild(script);}// 拼接参数params = {...params, cb};let arr = [];for (let k in params) {arr.push(`${k}=${params[k]}`);}script.src = `${url}?${arr.join('&')}`;document.body.appendChild(script);})}
后端服务
使用 express 框架
let express = require('express');let app = express();app.get('/say', function (req, res) {let { wd, cb } = req.query;console.log(wd);res.end(`${cb}('中文')`);})app.listen(3000);
