[乾貨]谷歌外掛跨域你可以瞭解下

紅茶配綠茶發表於2019-04-21

  這幾天谷歌更新到了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

參考文獻資料和帖子

chrome developer

Chrome外掛(擴充套件)開發全攻略

StackOverflow: chrome extension jsonp

MDN fetch

歷史文章傳送門

?‍?圖片壓縮Canvas

Vue嵌入iframe,iframe如何跨域呼叫vue內路由

記vue下懸浮貼合頂部實現

一加5t ,安卓p系統降級

編寫一個谷歌外掛翻譯Udemy+NetFlix字幕(相關)

相關文章