查资料的解释: JSONP数据交互协议一般用于Ajax跨域请求。Ajax直接请求普通文件存在跨域无权限访问的问题,然而web页面上调用js文件则不受是否跨域的影响(凡是拥有src该属性的标签都有跨域的能力),于是通过web端跨域访问数据的时候,设法把数据装进js格式的文件里面。获取之后便可以在web端进一步进行处理。
为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一 个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了
jsonp的整个过程就类似于前端声明好一个函数,后端返回执行函数。执行函数参数中携带所需的数据
个人理解:即就是因为我们在数据交互的时候需要的数据是需要跨域的,但是我们常用的ajax又不支持跨域请求,所有jsonp诞生了,jsonp就是一种非正式的传输协议,即通过web页面在调用js时可以跨域这个特点,我们把我们需要的数据放在远程服务端的js格式的文件里,这样web端 就可以获取了,获取后如何处理数据就是web端的事情,即可以写一个函数来处理,在后端调用这个函数就可以了,但是这个方法一个难点就是因为请求的时候我们每次使用这个jsonp是需要调用的函数的名字是不一样的,即我们可以在让这个函数的名字动态生成,然后再把这个名字传入后端执行
function jsonp(option) {
// 将用户通过对象命名空间传递进来的函数挂载到全局
var callbackName = 'itcast_' + Math.random().toString().substr(2) + Math.random().toString().substr(2)
!window.callbacks && (window.callbacks = {})
window.callbacks[callbackName] = function (data) {
option.success(data)
// 这里才意味着可以删除 script 标签了
// 这里可以直接使用 script ,原因是下面的变量提升,而且等这里使用 script 的时候,下面的代码早就执行结束了
document.body.removeChild(script)
}
// 1. 解决 url 问题
// 2. 解决回调处理函数问题
option.url = option.url + '?callback=callbacks.' + callbackName
//这里就是将动态生成的函数名通过URL路径传给后端(callbacks对象中的callbackName属性)
//即因为jsonp只支持get方法,就需要把数据写入到url中
var script = document.createElement('script')
script.src = option.url
// 将 script 上到 DOM 中
document.body.appendChild(script)
}
服务端:
const express = require('express')
const app = express()
app.get('/', (req, res, next) => {
console.log(`收到客户端请求了:${req.url}`)
var data = JSON.stringify({
foo: 'bar',
list: [1, 2, 3]
})
setTimeout(function () {
res.end(`${req.query.callback}(${data})`)
}, 1000)//获取路径的callback中的函数名,然后执行此函数
})
app.listen(3000, () => {
console.log('running...')
})