我们肯定学过,通过jsonp实现跨域请求,或是后台通过cors实现跨域请求,这次开拓一个新思路,使用chrome插件绕过浏览器同源策略
参考文档:http://chrome.cenchy.com/ https://developer.chrome.com/extensions
这是我后面做的一个ajax劫持跨域插件:https://www.jianshu.com/p/417ffc9bf1a2
DEMO效果图

原理图

background.html:background页是chrome://extensions/打开的,没有域,所以使用background请求不会被浏览器同源策略影响
content_script:通过谷歌插件注入到页面中的JS,使用他创建 EventDom 用于接收提交按钮的请求发送给background页
EventDom:因为content_script是无法直接与页面中的JS通信的,但是content_script可以操作页面中的dom,我们可以使用content_script创建一个EventDom.帮我们传递 事件 与 数据
1. 创建一个Chrome插件项目
创建manifest.json
{
"manifest_version": 2,
"name": "One-click Kittens",
"description": "This extension demonstrates a browser action with kittens.",
"version": "1.0",
"permissions": [
"http://127.0.0.1/",
"tabs"
],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"background": {
"scripts": [
"background.js"
]
},
"web_accessible_resources": [
"/*"
],
"content_scripts": [
{
"matches": [
"http://127.0.0.1/"
],
"js": [
"content_script.js"
]
}
]
}
2.background.js
background中通过chrome.runtime中的api,可以实现background和content_script之间的的通信
background使用tabId给对应的content_script发送消息
chrome.runtime.onMessage.addListener(function (e, sender) {
const { message, data } = e
const tabId = sender.tab.id
switch (message) {
case 'XHR':
request_proxy(data, tabId); break
}
})
function request_proxy({ url, method, data }, tabId) {
var XHR = new XMLHttpRequest()
console.log(tabId)
XHR.open(method, url)
XHR.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
XHR.send(data)
XHR.onreadystatechange = function () {
if (XHR.readyState === 4) {
chrome.tabs.sendMessage(tabId, {
message: 'XHR_response',
data: XHR.responseText
})
}
}
}
3.content_script
使用content_script创建EventDom。这里随便创建了个‘button’,没别的意思,任何标签都可以,只是使用element.dispatchEvent触发自定义事件。
然后通过触发(dispatchEvent)/响应(addEventListener)EventDom的事件与HTML页进行通信
并通过chrome的API 发送(chrome.runtime.sendMessage)/接收(chrome.runtime.onMessage.addListener)与background进行通信
dispatchEvent:https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/dispatchEvent
var button = document.createElement('button'); //创建EventDom
button.id = 'chrome_eventBus'
button.addEventListener('request_proxy', function (e) {
let { eventData } = e.target.dataset
eventData = JSON.parse(eventData)
let { url, method, data } = eventData
chrome.runtime.sendMessage('jencllhednpfafogdnjmoneilbiifloc', {
message: 'XHR',
data: {
url,
method,
data
}
})
})
document.body.appendChild(button);
const e = new Event('content_script_Ready') //触发自定义事件,在content_script注入并添加dom后,通知html页绑定Dom的事件
document.body.dispatchEvent(e)
chrome.runtime.onMessage.addListener(function (e, sender, sendResponse) {
console.log(e, sender, sendResponse)
const { message, data } = e
switch (message) {
case 'XHR_response':
response(data); break
}
})
function response(data) {
button.dataset['eventData'] = data
const e = new Event('response')
button.dispatchEvent(e)
}
4.Html页
html页就是你的项目,在这里你需要在content_script注入完毕后为EventDOM绑定事件。将请求通过EventDom发送给content_script
例如 登陆请求时dispatch EventDom的request_proxy事件,通过html5的dataset传递数据(也可以通过别的传,例如localstorage,indexdb。。。)
let iptUrl = document.getElementById('url')
let iptMethod = document.getElementById('method')
let iptData = document.getElementById('data')
let $ChromeEventBus = null //EventDom
document.getElementById('req-default').addEventListener('click', () => {
let url = iptUrl.value
let method = iptMethod.value
let data = iptData.value
let XHR = new XMLHttpRequest()
XHR.open(method, url)
XHR.send(JSON.stringify(data))
})
document.getElementById('req-background').addEventListener('click', () => {
let url = iptUrl.value
let method = iptMethod.value
let data = iptData.value
let option = {
url,
method,
data
}
$ChromeEventBus.dataset['eventData'] = JSON.stringify(option)
const e = new Event('request_proxy')
$ChromeEventBus.dispatchEvent(e)
})
document.body.addEventListener('content_script_Ready', Init) //当content_script注入完毕,并且创建EventBus后,进行事件的初始化
function Init() {
$ChromeEventBus = document.getElementById('chrome_eventBus')
$ChromeEventBus.addEventListener('response', function (e) {
let { eventData } = e.target.dataset
console.log('response', JSON.parse(eventData))
})
}