JSONP

124 阅读2分钟

JSONP能解决跨域的原理:

  • 一句话:<script>标签能受到限制的从其他的域加载

什么是JSONP

在讲跨域之前,先讲一下什么是JSONP,JSONP是“JSON with padding”的缩写,是web服务流行的JSON变体,JSONP看起来和JSON一样,只是包在一个函数调用中

callback({"name":"Apus"})

JSONP格式包括两个部分:

  • 回调
  • 数据

下面是一个典型的JSONP请求:

http://xxx//json/?callback=handleResponse

JSONP请求通常支持字符串的形式指定回调函数,比如这个例子就是指定回调函数handleReponse()

  • 下面举个例子
function handleRseponse(response){
	console.log()
	let script = document.createElement("script");
	script.src = "http://xxx//json/?callback=handleResponse";
	document.body.insertBefore(script,document.body.firstChild);
	
}
  • JOSNP是有效的js,所以JSONP会在响应加载之后立即执行

为什么 <script> 可以跨域?

浏览器的同源策略会限制大多数 AJAX 请求(如 XMLHttpRequestfetch),不能访问不同源的数据。但 <script><img><link> 等标签不受这个限制,因为它们被认为是安全的资源请求。同时他们的设计初衷就是为了引入加载外部资源。


JSONP 的工作原理:

场景:

你的网站(前端域名):http://a.com 目标 API(后端域名):http://b.com/data

由于不同源,直接用 fetch('http://b.com/data') 会被浏览器拦截。

JSONP 解决方案:

  1. 客户端定义一个全局函数

    function handleResponse(data) {
      console.log('接收到的数据:', data);
    }
    
  2. 动态插入 <script>,并把函数名通过查询参数传给服务器

    const script = document.createElement('script');
    script.src = 'http://b.com/data?callback=handleResponse';
    document.body.appendChild(script);
    
  3. 后端返回一段 JavaScript,而不是纯 JSON

    // 服务器返回内容:
    handleResponse({
      name: 'ChatGPT',
      age: 3
    });
    
  4. 浏览器执行这段脚本,自动调用你传给它的函数(handleResponse),完成跨域数据获取。


JSONP 的限制:

限制点描述
请求方式只能使用 GET 方法(不能 POST)
安全性差存在 XSS 风险,因为它执行的是远程返回的 JS 代码
只能读取数据无法用于跨域写入(例如提交表单数据)
服务端需配合必须按照特定格式返回 callbackName(data)
错误处理不友好script 标签加载失败不能拿到明确的错误信息

现代替代方案:

  • CORS(跨源资源共享):服务端设置 Access-Control-Allow-Origin 头,前端用 fetchaxios 即可发起跨域请求。
  • proxy(开发阶段代理):前端 dev server 将请求转发,绕过跨域。
//配置
  server: {
    proxy: {
      '/api/': {
        //target: 'http://192.168.1.31:8855',
        target: 'http://*****:8081',
        changeOrigin: true
      }
    }
  }

  • postMessage:iframe 或 window 之间通信。
  • WebSocketserver-side proxy 等也可以用于特定场景。

总结

JSONP 是通过 <script> 标签加载远程返回的 JS 脚本(包含数据),从而实现跨域读取数据的“黑科技”,本质是执行远程脚本,不是 AJAX。