jsonp的实现和应用场景

135 阅读3分钟

先来看一个问题👇

通过script标签可以拿到src链接里面的东西吗?

scr发出的是get请求

src链接里的东西需要分情况,一是为了加载外部数据,另一个是为了执行脚本代码。

1. 数据加载(外部数据)

JSONP是一种常用模式,需要服务端返回一个函数调用包裹着数据,这个函数需要预先在页面中定义。例如:

<script>
  function handleData(data) {
    console.log("Loaded data:", data);
  }
</script>
<script src="http://example.com/data?callback=handleData"></script>

在这个例子中,http://example.com/data 应该返回如 handleData({"key": "value"}) 的内容。

2. 执行脚本代码

脚本代码加载后直接使用即可,,无需手动“拿”内容。例如,如果你的script.js文件定义了函数doSomething(),加载后可以直接调用:

<script src="script.js"></script>
<script>
  doSomething();
</script>

前端接口跨域请求是老生常谈的话题。(不讲跨域通信)

通俗的讲,jsonp就是前端通过get请求,从服务端拿回了一个全局函数包括的json字符串,前端调用服务端返回的全局函数,拿到服务端返回的json作为参数。

接口获取外部数据(GET)

最近遇到一个调用外部数据的跨域问题,上面说过获取外部数据常用的就是jsonp,但是第三方的接口不友好,没有实现jsonp的回调逻辑,第三方不想改动。我的前端静态页面放在tomcat服务上,没法做接口的反向代理,也不想增加nginx代理服务。

两边都不想改,但是这样就无解了吗?非也!

跨域请求只是针对浏览器,后端发出的请求是不受跨域控制的,我们可以在自己的后端服务上写个接口A调用外部数据的接口B,然后前端调用我们自己服务的接口A,这样一来就把跨域问题转化到自己的服务上了,跨域问题就迎刃而解了。

jsonp跨域

实现jsonp的接口

https://www.kongfz.com/getModuleData?callback=test&moduleId=100&_=1717551687647

https://www.kongfz.com/getModuleData?moduleId=100&_=1717551687647

http://suggestion.baidu.com/su?wd=w

孔夫子旧书网这个做的兼容jsonp,很友好,加一个callback参数就可以。如果加了自定义的callback参数,就在返回体外面包一层,然后前端就可以在回调方法里取出来数据。

注意:jsonp要防止跨站脚本攻击(XSS)

通过 script 标签加载外部数据

    function loadScript(url, func) {
          var head = document.head || document.getElementByTagName('head')[0];
          var script = document.createElement('script');
          script.src = url;

          script.onload = script.onreadystatechange = function() {
              if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') {
                  func();
                  script.onload = script.onreadystatechange = null;
              }
          };

          head.insertBefore(script, head.children[0]);
      }
      // window.baidu = {
      //     sug: function(data) {
      //         console.log('data===', data);
      //     }
      // }
      
      // 自定义回调函数,获取接口返回数据
      function test(data) {
          console.log('data====', data);
      }
      loadScript('https://www.kongfz.com/getModuleData?callback=test&moduleId=100&_=1717551687647', function() {
          console.log('loaded==========')
      });

使用 ajax 调用外部数据

前端:

$.ajax({
    url: 'http://127.0.0.1:8001/list',
    method: 'get',
    dataType: 'jsonp', //=>执行的是JSONP的请求,这是jquery封装的ajax的功能
    success: res => {
        console.log(res);
    }
});

服务端:

let express = require('express'),
    app = express();
app.listen(8001, _ => { // 监听8001端口
    console.log('OK!');
});
app.get('/list', (req, res) => {
    let {
        callback = Function.prototype // callback如果没有,默认为空的函数
    } = req.query;
    let data = {
        code: 0,
        message: '返回jsonp请求的结果'
    };
    res.send(`${callback}(${JSON.stringify(data)})`); //=>后端需要处理好这样的数据格式
});

Jsonp需要后端支持

图片来源于网络 图片来源网络


我是 甜点cc,个人网站: home.i-xiao.space/vuepress-st…

升级打怪超厉害!

公众号:【看见另一种可能】