chenxiaochun / blog

🖋️ChenXiaoChun's blog
179 stars 15 forks source link

Chrome background script 实现跨域请求数据 #71

Open chenxiaochun opened 4 years ago

chenxiaochun commented 4 years ago

事情背景

最近开发一个 Chorme 插件,需要在https://item.jd.com上发起请求加载我们系统中的一个接口数据。一开始我是直接在页面中发起fetch请求,立刻就遇到了两个问题。

第一个问题是https://item.jd.com使用的是https协议。而我们的系统因为只能在内网访问,所以只是http协议的网站。当在页面中直接发起fetch请求时,浏览器会认为它不是一个安全的请求,会直接给你 block 掉:

Mixed Content: The page at 'https://item.jd.com/100011503930.html' was loaded over HTTPS, but requested an insecure resource 'http://hdj.jd.com/api/test'. This request has been blocked; the content must be served over HTTPS.

第二是即使解决了访问协议不同问题,依然不可能会从我们系统中拿到数据。因为还会有跨域的问题。

解决办法

后来改用在浏览器插件对应的content.js中使用chrome.extension.sendRequest发起请求,此函数支持两个参数:

title,用来表示发起的请求类型 api,是需要实际获取数据的 api 接口

chrome.extension.sendRequest({ title: 'getData', api: 'http://hdj.jd.com/getData.json' }, (resData: any) => {
  console.log(resData)
})

background.js中使用chrome.extension.onRequest.addListener监听发起的请求。它接受一个回调函数,其中第一个回调参数message就是上面的sendRequest传递进来的参数值

从它里面取出title值,用来判断是不是需要发起的请求

chrome.extension.onRequest.addListener((message, sender, sendResponse) => {
  if (message.title === 'getData') {
    fetch(message.api)
      .then((response) => {
        return response.json()
      })
      .then((data) => {
        sendResponse(data)
      })
  }
})

然后在background.js中正常发起fetch请求。将拿到的数据使用回调函数的第三个参数sendResponse返回到content.js中,也就能拿到数据了:

sendResponse(data)

这里要注意:在background.js中使用console.log打印的信息,是不会显示在当前页面的控制台中。你需要打开浏览器的扩展,点击”background page“打开一个独立的控制台,就能看到它的打印信息了

image

结语

这种方法理论上绕过了任何跨域限制,可以实现在任意网站中去请求另一个网站的数据(当然,前提是得有权限)。但是,如果要将插件发布到 Chrome AppStore 上,是否能过审,个人就不清楚了😂