JSONP的历史, 就是前端程序员为了优化用户体验而造成的javascript
首先来看一下浏览器看见什么会立刻进行请求?html
form
a
link
image
script
前三个就不说了,很简单~, 重点说下image
和script
前端
服务器端代码:java
response.setHeader('Content-Type', 'image/jpeg')
response.statusCode = 200
response.write(fs.readFileSync('./dog.jpeg'))
// 必须写入一个真实的图片,请求才会成功
复制代码
前端代码:node
let image = document.createElement('img')
image.src = '/pay'
image.onload = function(){
alert('打钱成功')
window.location.reload() // 刷新页面
}
image.onerror = function(){
alert('打钱失败')
}
// 利用图片的加载成功和失败,来判断请求是否成功.
复制代码
script
元素能够做为一种Ajax传输机制:只须设置script
元素的src
属性(假如它还没插入到document
中,须要插入进去),而后浏览器就会发送HTTP请求下载src属性程序员
所指向的URL。使用script
元素进行Ajax传输的一个主要缘由是,它不受同源策略的影响(不受域名限制),所以能够使用它们从其余的服务器请求数据,第二个缘由是包含JSON编码数据的响应体会解码。 这种使用script
元素做为Ajax传输的技术称为JSONPjson
说道script就和JSONP有关了后端
什么是JSONP?跨域
全称 JSON with Padding,用于解决AJAX跨域问题的一种方案。浏览器
因为同源策略的限制,浏览器只容许XmlHttpRequest请求当前源(域名、协议、端口)的资源,而对请求script资源没有限制。经过请求script标签实现跨域请求,而后在服务端输出JSON数据并执行回调函数,这种跨域的数据的方式被称为JSONP。
JSONP是一种非正式传输协议,该协议的一个要点就是容许用户传递一个callback参数给服务端,而后服务端返回数据时会将这个callback参数做为函数名来包裹住JSON数据,这样客户端就能够随意定制本身的函数来自动处理返回数据了。
具体步骤为:
请求方: xxx.com 的前端程序员(浏览器)
响应方: yyy.com 的后端程序员(服务器)
请求方建立 script, src指向响应方, 同时传递一个查询参数 ?callback=xxx
响应方根据查询参数 callback, 构造形如
这样的响应
浏览器接受到响应, 就会执行 xxx.call(undefined, '你要的数据')
那么请求方就知道了他要的数据
JSONP的行业要求
服务器代码
: 域名为jack.com:8002
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.env.PORT || 8888
if (!port) {
console.log('请指定端口号好不啦?\nnode server.js 8888 这样不会吗?')
process.exit(1)
}
var server = http.createServer(function (request, response) {
var parsedUrl = url.parse(request.url, true)
var pathWithQuery = request.url
var queryString = ''
if (pathWithQuery.indexOf('?') >= 0) {
queryString = pathWithQuery.substring(pathWithQuery.indexOf('?'))
}
var path = parsedUrl.pathname
var query = parsedUrl.query
var method = request.method
if (path === '/') { // 当请求路径为 '/' 时, 返回一个index.html
var string = fs.readFileSync('./index.html', 'utf8')
var amount = fs.readFileSync('./db', 'utf8')
string = string.replace('&&&amount&&&', amount)
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.end(string)
} else if (path === '/pay') { // 当请求路径问 '/pay'时
var amount = fs.readFileSync('./db', 'utf8')
var newAmount = amount - 1
fs.writeFileSync('./db', newAmouznt)
response.setHeader('Content-Type', 'application/javascript')
response.statusCode = 200
response.write(` ${query.callback}.call(undefined,'success') `)
response.end()
} else {
response.statusCode = 404
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.end()
}
})
server.listen(port)
复制代码
上面的代码
response.write(${query.callback}.call(undefined,'success')
)
第二个参数为string, 也能够叫作StringP, 若是换成JSON,就是JSONP.
${query.callbackName}.call(undefined,{
"success": true,
"left": ${newAmount}
})
// JSON: { "success": true,"left": ${newAmount}}
// 左padding: ${query.callbackName}.call(undefined,
// 右padding: )
复制代码
前端代码
: 域名为frank.com:8001
<h5>您的帐户余额是 <span id='amount'>&&&amount&&&</span></h5>
<button id="button">付款</button>
<script> button.addEventListener('click', function (e) { let script = document.createElement('script') let functionName = 'frank' + parseInt(Math.random() * 100000, 10) // 前端声明一个函数, 给后端调用, 函数名经过callback传递给后端 window[functionName] = function (result) { // 后端返回result, 能够是json, 能够是string if (result === 'success') { alert(`我获得的结果是${result}`) amount.innerText = amount.innerText - 1 } else { alert('fail') } } script.src = 'http://jack.com:8001/pay?callback=' + functionName document.body.appendChild(script) script.onload = function (e) { e.currentTarget.remove() // 移除script delete window[functionName] } script.onerror = function () { alert('打钱失败') e.currentTarget.remove() delete window[functionName] } }) </script>
复制代码
由于JSONP是经过动态建立script来实现的, 动态建立的script只能用GET,不能用POST.