這幾天谷歌更新到了73版本後,有人提醒我之前寫的谷歌翻譯外掛報錯,看了下是跨域下cors報紅提醒,經過我多次嘗試解決,最終得以解決,此篇僅以我的解決措施,以及一些嘗試來講述這一過程。
谷歌外掛編寫傳送門
首先介紹下吧,谷歌外掛多數時候,是對谷歌瀏覽器功能的一些擴充,甚至直接依賴本身實現一些桌面端應用等,常見的有日曆,頁面重新整理,郵箱等,強大一點的有遠端桌面控制等,當我們科學上網的時候,大家可以去找找,有點廢話
跨域問題
谷歌外掛是一個沙箱系統。
借官方圖一樣用,background我稱之為後臺,contentscript為內容體。之前整個外掛作用機制如圖:
在之前版本中,通過官方給出的配置即可解決跨域,在content中請求資料,並操作瀏覽器頁面的dom,配置如下,這可能是多數開發者之前的配置,也是查閱很多資料,大家給出的解決方法,然而此次我是失效了,因為之前已配置好。
這是流行的方式配置方式,你需要請求那個api的介面,就寫上地址即可,之後谷歌外掛的機制,會正常以json的形式請求。 更新版本後,控制檯爆紅:Access to fetch at 'another-site.com/' from origin 'example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
解決措施
暴力解決法,此法堪稱殺豬刀,直接關了瀏覽器的安全機制
Chrome49之後的版本:Windows:
1.關閉所有的chrome瀏覽器。
2.新建一個chrome快捷方式,右鍵“屬性”,“快捷方式”選項卡里選擇“目標”,新增 --args --disable-web-security --user-data-dir
3.通過快捷方式開啟谷歌瀏覽器
MAC:
開啟終端,確保chrome 已經完全退出。
open -a /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir
複製程式碼
之後瀏覽器會提示
上述方法,臨時過渡了幾天。之後我想到的是jsonp解決方式,因為我所需要的資源是提供了JSONP的請求方式,於是我自信的將請求方式改為了jsonp,模擬程式碼如下:
<!--start.js-->
function jsonpFunc(jsonpParams){
console.log(jsonpParams)
}
$.ajax({
url: 'http://example.com',
data:
{
apiKey:apikey,
sign:sign,
to:'zh',
query:'Hello world'
},
dataType: "jsonp",
jsonp:'jsonpParams',
jsonpCallback:'jsonpFunc',
//jsonpCallback:jsonpFunc, // Uncaught ReferenceError: jQuery17105683612572029233_1323808231542 is not defined
success: function(msg){
newNode.src = msg.data;
},
error: function(msg){
console.log(msg.data);
}
})
複製程式碼
在這裡我遇到兩個問題,一個是回撥函式加引號,該函式回去找瀏覽器中j上jonpFunc函式,在當前檔案內,我定義的函式,壓根就不再對方的考慮範圍內,我試過在background.js中定義,window下掛載,由於沙箱的規則,無一生效。 如果直接呼叫函式,不加引號,則瀏覽器控制檯會報錯上方註釋資訊,並且點選定位能看到介面返回的資訊,但是遺憾的是我無法取得,並對它進行處理。
在解決過程中找到一個很好的帖子【乾貨】Chrome外掛(擴充套件)開發全攻略,在這兩張圖中我找到了思路
這就是解決方案,並且可以避免跨域請求的問題~ 只要保持雙方間的通訊即可,注意其中有個限制是,只能存在一個佇列,無論定義幾個這種佇列 當只要有個一個先到達B,則另外一個取消通訊,開始下輪。針對此情況我不能單獨寫幾個佇列,只能通過一組這種雙方通訊的方式,裡面做情況拆分<!--background.js 不可操作瀏覽器頁面,可跨域-->
// 監聽函式 API,獲取從content_script傳遞過來的內容
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
var query = '',_promise=null;
if(request.currentRequstName == 'yandex'){
query = request.subtitle;
var apiKey = request.apiKey;
var to = request.configInfo.aimLang == 'undefined' ? 'zh' : request.configInfo.aimLang;
if (query == '') return
_promise = ajaxThen("https://translate.yandex.net/api/v1.5/tr.json/translate", {
key: apiKey,
text: query,
lang: to
})
}else if(request.currentRequstName == "baidu"){ // 分類請求
// ...
}else if(request.currentRequstName == "youdao"){
// ...
}
});
function ajaxThen(url, params) { // 請求封裝
var dtd = $.Deferred();
$.ajax({
url: url,
type: 'post',
data: params,
dataType: 'json'
}).then(function (data) {
dtd.resolve(data);
}, function () {
toastr.error("submit failure", "oprate failure");
dtd.reject();
});
return dtd.promise();
}
<!--start.js 可操作瀏覽器頁面,不可跨域-->
// 傳送資料到background,讓它取請求資料
chrome.runtime.sendMessage({
currentRequstName: 'youdao', // "baidu","yandex"
apiKey: apiKey,
subtitle: query,
configInfo: configInfo,
sign: sign,
from: from,
salt: salt
}, function (response) {
// when background get info
});
// 接收得到background.js頁面得到的資料,之後就是操作了
var beforeGet = null;
// 監聽函式,獲取衝backgroud傳遞過來的資料
chrome.extension.onMessage.addListener(
function (request, sender, sendResponse) {
if (beforeGet != request) { // 避免重複操作
beforeGet = request;
console.log("%c%s","color: red; background: yellow; font-size: 24px;",JSON.stringify(request[0]));
// 根據不同請求方式,來選擇操作模式
if (request[2] == 'yandex') {
yandexSendOkThenChangeSubtitle(request)
} else if (request[2] == "baidu") {
baiduSendThenChangeSubtitle(request)
} else if (request[2] == "youdao") {
youdaoSendThenChangeSubtitle(request)
}
}
}
);
複製程式碼
以上就是核心實現,之前的邏輯複用即可。
終
此次修復完畢,希望撐一段時間,此專案開源 chrome-extension-udemy-translate 維持八個多月,體會到了當中的苦與樂,希望能真正幫到一些朋友,開源不易(一直開一直爽?
See Ya
參考文獻資料和帖子
StackOverflow: chrome extension jsonp
歷史文章傳送門
Vue嵌入iframe,iframe如何跨域呼叫vue內路由