可能是最好的跨域解决方案 !

小哈学Java

共 7255字,需浏览 15分钟

 ·

2021-11-19 10:26

点击关注公众号,Java干货及时送达👇


作者 | campcc

来源 | https://github.com/campcc/blog


今天我们来聊一个老生常谈的话题,跨域!又是跨域,烦不烦 ?网上跨域的文章那么多,跨的我眼睛都疲劳了,不看了不看了 🤣 别走...我尽量用最简单的方式将常见的几种跨域解决方案给大家阐释清楚,相信认真看完本文,以后不管是作为受试者还是面试官,对于这块的知识都能够游刃有余。

什么是“跨源”

**不是讲跨域吗 ?怎么又来个“跨源” ?字都能打错的 ?*😄...稍安勿躁,其实我们平常说的跨域是一种狭义的请求场景,简单来说,就是“跨“过*浏览器的同源策略[1]去请求资“源”,所以我们叫它“跨源”也没啥问题。那么,跨源,源是什么?浏览器的同源策略什么是同源?协议,域名,端口都相同就是同源干巴巴的,能不能举个栗子?栗子:),有的有的

const url = 'https://www.google.com:3000'

比如上面的这个 URL,协议是:https,域名是 www.google.com,端口是[2] 3000。不同源了会怎么样?会有很多限制,比如

  • Cookie,LocalStorage,IndexDB 等存储性内容无法读取
  • DOM 节点无法访问
  • Ajax 请求发出去了,但是响应被浏览器拦截了

我就想请求个东西,至于吗,为什么要搞个这么个东西限制我?基于安全考虑,没有它,你可能会遇到

  • Cookie劫持,被恶意网站窃取数据
  • 更容易受到 XSS,CSRF 攻击
  • 无法隔离潜在恶意文件
  • ... ...

所以,得有。正是因为浏览器同源策略的存在,你的 Ajax 请求有可能在发出去后就被拦截了,它还会给你报个错:

✘ Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been block by CORS,
  policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

这种发出去拿不到响应的感受,就像你在网上冲浪时,被一股神秘的东方力量限制了一样:

图片

非常难受,所以,我们接下来就来看看怎么用科学的方法上网(啊呸,科学的方法解决跨域的问题)。

JSONP

这玩意儿就是利用了 `` 标签的 src 属性没有跨域限制的漏洞,让我们可以得到从其他来源动态产生的 JSON 数据。为什么叫 JSONP ?JSONP 是 JSON with Padding 的缩写,额,至于为什么叫这个名字,我网上找了下也没个标准的解释,还望评论区的各位老哥知道的赶紧告诉我: ) 怎么实现 ?具体实现思路大致分为以下步骤

  • 本站的脚本创建一个 元素,src 地址指向跨域请求数据的服务器
  • 提供一个回调函数来接受数据,函数名可以通过地址参数传递进行约定
  • 服务器收到请求后,返回一个包装了 JSON 数据的响应字符串,类似这样:callback({...})

浏览器接受响应后就会去执行回调函数 callback,传递解析后的 JSON 对象作为参数,这样我们就可以在 callback 里处理数据了。实际开发中,会遇到回调函数名相同的情况,可以简单封装一个 JSONP 函数:

function jsonp({ url, params, callback }) {
  return new Promise((resolve, reject) => {
    // 创建一个临时的 script 标签用于发起请求
    const script = document.createElement('script');
    // 将回调函数临时绑定到 window 对象,回调函数执行完成后,移除 script 标签
    window[callback] = data => {
      resolve(data);
      document.body.removeChild(script);
    };
    // 构造 GET 请求参数,key=value&callback=callback
    const formatParams = { ...params, callback };
    const requestParams = Object.keys(formatParams)
      .reduce((acc, cur) => {
        return acc.concat([`${cur}=${formatParams[cur]}`]);
      }, [])
   .join('&');
 // 构造 GET 请求的 url 地址
    const src = `${url}?${requestParams}`;
    script.setAttribute('src', src);
    document.body.appendChild(script);
  });
}

// 调用时
jsonp({
  url: 'https://xxx.xxx',
  params: {...},
  callback: 'func',
})

我们用 Promise 封装了请求,使异步回调更加优雅,但是别看楼上的洋洋洒洒写了一大段,其实本质上就是:

'https://xxx.xxx.xx?key=value&callback=xxx'>