这几天谷歌更新到了73版本后,有人提醒我之前写的谷歌翻译插件报错,看了下是跨域下cors报红提醒,经过我多次尝试解决,最终得以解决,此篇仅以我的解决措施,以及一些尝试来讲述这一过程。
谷歌插件编写传送门
首先介绍下吧,谷歌插件多数时候,是对谷歌浏览器功能的一些拓展,甚至直接依赖本身实现一些桌面端应用等,常见的有日历,页面刷新,邮箱等,强大一点的有远程桌面控制等,当我们科学上网的时候,大家可以去找找,有点废话
跨域问题
谷歌插件是一个沙箱系统。
之前整个插件作用机制如图:
在之前版本中,通过官方给出的配置即可解决跨域,在content中请求数据,并操作浏览器页面的dom,配置如下,这可能是多数开发者之前的配置,也是查阅很多资料,大家给出的解决方法,然而此次我是失效了,因为之前已配置好。
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插件(扩展)开发全攻略,在这两张图中我找到了思路
<!--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内路由