您的位置:首页 > 其它

Chrome扩展及应用开发 入门笔记(二)跨域请求

2015-07-01 19:06 519 查看

manifest.json:

文件可以告诉Chrome关于这个扩展的相关信息,它是整个扩展的入口,也是Chrome扩展必不可少的部分

注:

Google的官方文档中对于扩展和应用给出了两个不同的Manifest介绍界面,这是因为有些属性只能由扩展使用,而有些属性只能由应用使用。

如果这两者同时出现在同一个Manifest文件中,就会使Chrome困惑,不知是按照扩展对待这个程序还是按照应用来对待这个程序。

但无论是扩展还是应用,它们的Manifest又有很多共有的属性。

manifest.json模板:

Chrome扩展的Manifest必须包含
name
version
manifest_version
属性,目前来说
manifest_version
属性值只能为数字2,对于应用来说,还必须包含
app
属性。

其他常用的可选属性还有
browser_action
page_action
background
permissions
options_page
content_scripts

所以我们可以保留一份manifest.json模板,当编写新的扩展时直接填入相应的属性值。

可以应对大部分的扩展的模板:

{
"app": {
"background": {
"scripts": ["background.js"]
}
},
"manifest_version": 2,
"name": "My Extension",
"version": "versionString",
"default_locale": "en",
"description": "A plain text description",
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
},
"browser_action": {
"default_icon": {
"19": "images/icon19.png",
"38": "images/icon38.png"
},
"default_title": "Extension Title",
"default_popup": "popup.html"
},
"page_action": {
"default_icon": {
"19": "images/icon19.png",
"38": "images/icon38.png"
},
"default_title": "Extension Title",
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["http://www.google.com/*"],
"css": ["mystyles.css"],
"js": ["jquery.js", "myscript.js"]
}
],
"options_page": "options.html",
"permissions": [
"*://www.google.com/*"
],
"web_accessible_resources": [
"images/*.png"
]
}
在官方文档中可以找到完整的Manifest属性列表,扩展在https://developer.chrome.com/extensions/manifest

操作用户正在浏览的页面:

实际上就是对用户当前浏览页面的DOM进行操作。通过Manifest中的
content_scripts
属性可以指定将哪些脚本何时注入到哪些页面中,

当用户访问这些页面后,相应脚本即可自动运行,从而对页面DOM进行操作。

Manifest的
content_scripts
属性值为数组类型,数组的每个元素可以包含:

matches
//定义了哪些页面会被注入脚本


exclude_matches//定义了哪些页面不会被注入脚本


css /js //对应要注入的样式表和JavaScript


run_at//何时进行注入


all_frames
//脚本是否会注入到嵌入式框架中


include_globs//


exclude_globs
//全局URL匹配,最终脚本是否会被注入由
matches
exclude_matches
include_globs
exclude_globs
的值共同决定。

简单的说,如果URL匹配
mathces
值的同时也匹配
include_globs
的值,会被注入;如果URL匹配
exclude_matches
的值或者匹配
exclude_globs
的值,则不会被注入。

content_scripts
中的脚本
只是共享页面的DOM1,而并不共享页面内嵌JavaScript的命名空间。也就是说,如果当前页面中的JavaScript有一个全局变量
a
content_scripts
中注入的脚本也可以有一个全局变量
a
,两者不会相互干扰。

当然你也无法通过
content_scripts
访问到页面本身内嵌JavaScript的变量和函数。


跨域请求:

跨域指的是JavaScript通过
XMLHttpRequest
请求数据
时,调用JavaScript的页面所在的域和被请求页面的域不一致。

对于网站来说,浏览器出于安全考虑是不允许跨域。另外,对于域相同,但端口或协议不同时,浏览器也是禁止的。下表给出了进一步的说明:

URL说明是否允许请求
http://a.example.com/
http://a.example.com/a.txt
同域下允许
http://a.example.com/
http://a.example.com/b/a.txt
同域下不同目录允许
http://a.example.com/
http://a.example.com:8080/a.txt
同域下不同端口不允许
http://a.example.com/
https://a.example.com/a.txt
同域下不同协议不允许
http://a.example.com/
http://b.example.com/a.txt
不同域下不允许
http://a.example.com/
http://a.foo.com/a.txt
不同域下不允许
解决:

但这个规则如果同样限制Chrome扩展应用,就会使其能力大打折扣,所以Google允许Chrome扩展应用不必受限于跨域限制。

但出于安全考虑,需要在Manifest的
permissions
属性中声明需要跨域的权限。


比如,如果我们想设计一款获取维基百科数据并显示在其他网页中的扩展,就要在Manifest中进行如下声明:

{
...
"permissions": [
"*://*.wikipedia.org/*"
]
}


这样Chrome就会允许你的扩展在任意页面请求维基百科上的内容了。

可以利用如下的代码发起异步请求:

function httpRequest(url, callback){
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callback(xhr.responseText);
}
}
xhr.send();
}


这样每次发起请求时,只要调用
httpRequest
函数,并传入要请求的URL和接收返回结果的函数就可以了。为什么要使用
callback
函数接收请求结果,而不直接用
return
将结果作为函数值返回呢?因为
XMLHttpRequest
不会阻塞下面代码的运行。

为了更加明确地说清上述问题,让我们来举两个例子。

function count(n){
var sum = 0;
for(var i=1; i<=n; i++){
sum += i;
}
return sum;
}

var c = count(5)+1;
console.log(c);

这个例子会在控制台显示16,
因为:<code>count</code>函数是一个阻塞函数,在它没有运行完之前它会阻塞下面的代码运行,
所以直到<code>count</code>计算结束后才将结果返回后再加<code>1</code>赋给变量<code>c</code>,最后将变量<code>c</code>的值打印出来

unction httpRequest(url){
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
return xhr.responseText;
}
}
xhr.send();
}

var html = httpRequest('test.txt');
console.log(html);

虽然请求的资源内容为<code>Hello World!</code>,但却并没有正确地显示出来

原因:
<code>httpRequest</code>函数不是一个阻塞函数,在它没运行完之前后面的代码就已经开始运行,
这样<code>html</code>变量在<code>httpRequest</code>函数没返回值之前就被赋值,所以最终的结果必然就是<code>undefined</code>了。

既然这样,如何将非阻塞函数的最终结果传递下去呢?方法就是使用回调函数。在Chrome扩展应用的API中,大部分函数都是非阻塞函数,

所以使用回调函数传递结果的方法以后会经常用到。

让我们来用回调函数的形式重写第二个例子:

function httpRequest(url, callback){
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callback(xhr.responseText);
}
}
xhr.send();
}

var html;
httpRequest('test.txt', function(result){
html = result;
console.log(html); <code>httpRequest</code>函数运行的结果已经被正确地打印出来了。
});


实战编写一款显示用户IP的扩展:

{
"manifest_version": 2,
"name": "查看我的IP",
"version": "1.0",
"description": "查看我的电脑当前的公网IP",
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
},
"browser_action": {
"default_icon": {
"19": "images/icon19.png",
"38": "images/icon38.png"
},
"default_title": "查看我的IP",
"default_popup": "popup.html"
},
"permissions": [
"http://sneezryworks.sinaapp.com/ip.php" //的Manifest定义了这个扩展允许对http://sneezryworks.sinaapp.com/ip.php发起跨域请求
]
}


popup.html:

<html>
<head>
<style>
* {
margin: 0;
padding: 0;
}

body {
width: 400px;
height: 100px;
}

div {
line-height: 100px;
font-size: 42px;
text-align: center;
}
</style>
</head>
<body>
<div id="ip_div">正在查询……</div>
<script src="js/my_ip.js"></script>//js文件夹下有my_ip.js文件
</body>
</html>


my_ip.js:注 此 js获取 IP实践后发现不行

function httpRequest(url, callback){
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callback(xhr.responseText);
}
}
xhr.send();
}

httpRequest('http://sneezryworks.sinaapp.com/ip.php', function(ip){
document.getElementById('ip_div').innerText = ip;
});


结果:



源码地址

https://github.com/xiaohuhuanxiang/chromedev/tree/chrome/getIP

安全问题:

作为一个开发者,安全问题永远都不应被轻视。在你从外域获取到数据后,不要轻易作为当前页面元素的
innerHTML
直接插入,更不要用
eval
函数去执行它
,否则很可能将用户置于危险的境地。如果要将请求到的数据写入页面,可以使用
innerText
,就像我们这个查看IP的扩展那样。如果是JSON格式是数据就使用
JSON.parse
函数去解析。为了避免请求数据返回的格式错误,结合
try-catch
一起使用也是不错的选择。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: