chrome 在 73 版本後,限制了 content-script 跨域請求目前只有一個解決辦法,廢棄 content-script 跨域請求,使用background.js 執行跨域請求,但這樣有個最大的問題是沒法支持文件上傳javascript
問題的背景如上。原先的yapi插件支持兩種方式, 第一個是在content-script中進行請求,另一個則是background進行請求,可是background須要依賴於content-script將請求的內容傳遞給到background中。java
一開始以爲這個問題其實不難解決,由於在content-script已經將全部的請求內容都獲取到了,包括上傳的文件(formdata格式)因此只要將內容傳遞給到background中便可chrome
function sendAjaxByBack(id, req, successFn, errorFn) {
successFns[id] = successFn;
errorFns[id] = errorFn;
connect.postMessage({
id: id,
req: req
});
}
複製代碼
只要將文件的formdata內容賦值到req中便可,結果發如今background中接收到的formdata的數據爲空。翻閱了下google關於postMessage的api後發現以下: api
考慮了下,並非說file的對象必定要用formdata已經包裝傳遞,是否能夠變成字符串的形式呢,這個時候咱們能夠想到能夠把文件轉換成base64進行傳遞,而後再解析回原先的文件對象便可了。跨域
因此代碼以下數組
function sendAjaxByBack(id, req, successFn, errorFn) {
successFns[id] = successFn;
errorFns[id] = errorFn;
if (req.headers['Content-Type'] === 'multipart/form-data') {
var formDatas = []
if (req.data) {
for (var name in req.data) {
formDatas.push({name, value: req.data[name], is_file: false});
}
}
if (req.files) {
let allPromise = [];
for (var name in req.files) {
let fileTransfer = new Promise(function (resolve, reject){
var files = document.getElementById(req.files[name]).files;
let file = files[0]
var reader = new FileReader();
reader.name = name;
reader.fileName = file.name;
reader.onload = function () {
resolve({name: this.name, value: this.result,is_file: true, fileName: this.fileName});
}
reader.readAsDataURL(file);
})
allPromise.push(fileTransfer);
}
Promise.all(allPromise).then(function(result){
formDatas = formDatas.concat(result);
req.formDatas = formDatas;
connect.postMessage({
id: id,
req: req,
});
})
}else {
req.formDatas = formDatas;
connect.postMessage({
id: id,
req: req,
});
}
} else {
connect.postMessage({
id: id,
req: req
});
}
}
複製代碼
針對文件的發送轉換成base64進行存儲分別依次放到formdata的一個數組中,這裏要區別部分是文件的類型,部分是普通的字符串,因此咱們這裏經過一個is_file進行區別是不是文件類型。app
background.js中的處理post
if (!req.headers['Content-Type'] || req.headers['Content-Type'] == 'application/x-www-form-urlencoded') {
req.headers['Content-Type'] = 'application/x-www-form-urlencoded';
req.data = formUrlencode(req.data);
} else if (req.headers['Content-Type'] === 'multipart/form-data') {
delete req.headers['Content-Type'];
let formDatas = new FormData();
for (var item of req.formDatas) {
if (item.is_file) {
formDatas.append(item.name, dataURLtoFile(item.value, item.fileName))
}else {
formDatas.append(item.name, item.value);
}
}
req.data = formDatas;
} else if (typeof req.data === 'object' && req.data) {
req.data = JSON.stringify(req.data);
}
複製代碼
針對content-Type爲multipart/form-data的處理,聲明一個formdata進行存儲對應的數據ui
如此便可解決文件經過background進行文件上傳的問題this