原生js实现JSONP

Table of Contents

介绍

JSONP是JSON with Padding(填充式JSON或参数式JSON)的简写,是一种非常常用的跨域请求方式。主要原理是利用了script 标签可以跨域请求的特性,由其 src属性发送请求到服务器,服务器返回JavaScript 代码,浏览器接受响应,然后就直接执行了,这和通过 script 标签引用外部文件的原理是一样的。

JSONP由两部分组成:回调函数数据,回调函数是当响应到来时应该在页面中调用的函数,回调函数的名字一般在请求中指定。当服务器响应时,服务器端就会把该函数和数据拼成字符串返回。

JSONP 的请求过程

  • 请求阶段:浏览器创建一个 script 标签,并给其src 赋值(类似 http://example.com/api/?callback=jsonpCallback)。
  • 发送请求:当给scriptsrc赋值时,浏览器就会发起一个请求。
  • 数据响应:服务端将要返回的数据作为参数和函数名称拼接在一起(格式类似”jsonpCallback({name: 'abc'})”)返回。当浏览器接收到了响应数据,由于发起请求的是 script,所以相当于直接调用 jsonpCallback 方法,并且传入了一个参数。

服务端交互示意图

server1代码(Nodejs实现)

var Koa = require('koa');
var Router = require('koa-router');
var querystring = require('querystring');
var app = new Koa();
var router = new Router();

//处理get请求
router.get('/get', async function(ctx){
    var params = querystring.parse(ctx.request.url.split('?')[1]);
    var data = { message: "我是" + ctx.request.header.host + ",我收到了你的get请求!!!" }
    ctx.status=200;
    ctx.body=params['callback']+'('+JSON.stringify(data)+');';
});

app
    .use(router.routes())
    .use(router.allowedMethods())

app.listen(3000);

server2代码

var Koa = require('koa');
var Router = require('koa-router');
var render = require('koa-art-template');
var path = require('path');

var app = new Koa();
var router = new Router();

//配置模板引擎
render(app, {
    root: path.join(__dirname, 'views'),
    extname: '.html',
    debug: process.env.NODE_ENV !== 'production',
});

router.get('/index.html', async function (ctx) {
    await ctx.render('server2');
});

app.use(router.routes()).use(router.allowedMethods());
app.listen(4000);

前端代码

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <title>原生js实现</title>
</head>

<body>
    <div><button>点击我发送get请求</button></div>
    <!-- <script>
        function jsonpcallback(response){
            alert(response.message);
        }
    </script>
    <script src="http://127.0.0.1:3000/get?callback=jsonpcallback" type="text/javascript"></script> -->
</body>
<script>
    document.getElementsByTagName('button')[0].addEventListener('click', function () {
        ajax('http://127.0.0.1:3000/get', function(response){
            alert(response.message);
        });
    });
    function ajax(url, callback){
        var jsonp=document.createElement('script');
        jsonp.type = 'text/javascript';
        jsonp.src=url+'?callback=jsonpcallback';
        jsonpcallback = function(response){
            callback(response);
        };
        document.getElementsByTagName('head')[0].appendChild(jsonp);
    }
</script>

</html>

分析

其实上述过程可以总结为:

function jsonpcallback(response){
    alert(response.message);
}
jsonpcallback({"message":"我是127.0.0.1:3000,我收到了你的get请求!!!"});