带你用Node了解JSONP实现原理

本文介绍了JSONP的概念,它是为了解决JavaScript跨域请求的问题。通过模拟JSONP请求,展示了如何在Node.js中实现JSONP,并利用Promise封装了一个包含超时逻辑的JSONP函数。通过实例演示,验证了函数的正确性。
摘要由CSDN通过智能技术生成

1、JSONP是什么,解决了什么问题

JSONP 指的是 JSON with Padding。

由于跨域政策,从另一个域请求文件会引起问题。

从另一个域请求外部脚本没有这个问题。

JSONP 利用了这个优势,并使用 script 标签替代 XMLHttpRequest 对象。——w3c

Web页面上调用js文件时不受是否跨域的影响(不仅如此,我们还发现凡是拥有src这个属性的标签都拥有跨域的能力,比如 、、)所以JSONP解决的问题是请求跨域的问题。如果还是不理解可以自行百度相关解释,这里不做重点解释,主要是看一下实现。

2、如何实现JSONP

了解了JSONP是什么,我们就来模拟一下一个JSONP请求。JSONP的实现方式一般是在请求参数里添加"callback=函数名"的方式,这里我们使用nodejs作为服务。

首先搭建一个本地服务,这里使用express,先全局安装一下express

npm install express -g

然后创建一个文件夹,进入文件夹目录下执行下面命令

npm init

这里一路回车就可以

安装express

npm install express -s

这个时候我们的目录是这样的

├── node_modules
├── package-lock.json
└── package.json

在根目录下新建index.js文件

├── index.js
├── node_modules
├── package-lock.json
└── package.json

文件内容如下

var express = require('express')

//2. 创建express服务器
var server = express()

//3. 访问服务器(get或者post)
//参数一: 请求根路径
//3.1 get请求
server.get('/', function(request, response) {
  // console.log(request)
  response.send({ name: 'starfishing' })
})
server.get('/json/getUser', function(request, response) {
  console.log(request.query)
  let callback = request.query.callback
  // console.log(request)
  let str = callback + "({'name':'starfishing','age':22})"
  response.send(str)
})
//4. 绑定端口
server.listen(4040)
console.log('启动4040')

到这里我们的服务就搭好了,执行node index.js启动服务

然后新建一个html页面,内容如下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>JSONP测试</title>
  </head>
  <body>
     <script>
    function jsonp(data){
      // 这是我们的回调函数
      console.log(data.name,data.age)
    }
    </script>
    <script src="http://localhost:4040/json/getUser/?callback=jsonp"></script>
  </body>
</html>

在浏览器打开页面,调出控制台,可以看到我们回调函数打印出的内容

3、jsonp进阶,使用promise实现jsonp

我们会基于promise封装一个JSONP函数,包括请求超时逻辑,下面贴一下代码

      function JSONP(url, params, overtimes) {
        return new Promise(function(resolve, reject) {
          let query = []
          //注册回调函数
          let callbackName = 'jsonp' + Math.ceil(Math.random() * 1000000)
          window[callbackName] = function(json) {
            head.removeChild(script) //移除scipt标签
            script.timer ? clearTimeout(script.timer) : false //清除超时计时器
            window[callbackName] = null
            resolve(json) //成功处理
          }

          for (let key in params) {
            query.push(key + '=' + params[key])
          }
          query.push('callback=' + callbackName)
          let remote = url + '/?' + query.join('&')
          let script = document.createElement('script')
          script.src = remote
          let head = document.getElementsByTagName('head')[0]
          head.appendChild(script)

          script.onerror = function(err) {
            if (window && window[callbackName]) {
              delete window[callbackName]
            }
            try {
              head.removeChild(script)
            } catch {}

            reject(err)
          }

          if (overtimes) {
            script.timer = setTimeout(function() {
              if (window && window[callbackName]) {
                delete window[callbackName]
              }
              try {
                head.removeChild(script)
              } catch {}

              reject({ timer: 'overtime' })
            }, overtimes)
          }
        })
      }

然后对我们的node服务做一下改造来验证我们的函数

var express = require('express')

//2. 创建express服务器
var server = express()

//3. 访问服务器(get或者post)
//参数一: 请求根路径
//3.1 get请求
server.get('/', function(request, response) {
  // console.log(request)
  response.send({ name: 'xiaoxin' })
})
server.get('/json/getUser', function(request, response) {
  console.log(request.query)
  let callback = request.query.callback
  let str = callback + "({'name':'starfishing','age':22})"
  // 下面是验证正常返回的情况
  response.send(str)

  // 下面是验证服务器错误的情况
  // response.status(500)

  // 下面验证超时
  // setTimeout(function() {
  //   response.send(str)
  // }, 6000)
})
//4. 绑定端口
server.listen(4040)
console.log('启动4040')

最后把新的函数放到HTML文件中进行验证

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>JSONP测试</title>
  </head>
  <body>
    <script>
      function JSONP(url, params, overtimes) {
 				// 这里就是我们上面封装的函数,直接拷贝到这里,避免篇幅太长,这里就不拷进来了
      }
    </script>
    <script>
      JSONP('http://localhost:4040/json/getUser', { name: 'haha' }, 5000)
        .then(data => {
          console.log(data)
        })
        .catch(err => {
          console.log(err)
        })
    </script>
  </body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值