# 跨域 XMLHttpRequest 请求
普通网页能够使用[XMLHttpRequest](http://www.w3.org/TR/XMLHttpRequest/)对象发送或者接受服务器数据, 但是它们受限于[同源策略](http://en.wikipedia.org/wiki/Same_origin_policy). 扩展可以不受该限制. 任何扩展只要它先获取了跨域请求许可,就可以进行跨域请求。
**注意:**页面内容脚本不能直接发起跨域请求. 然而, 任何一个页面内容脚本都可以发送消息给父扩展,请求父扩展发起一次跨域请求。关于使用这一技术的例子,请参照[contentscript_xhr example](http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/howto/contentscript_xhr).
## 扩展所属域
每个正在运行的扩展都存在于自己独立的安全域里. 当没有获取其他权限时,扩展能够使用XMLHttpRequest获取来自安装该扩展的域的资源. 例如, 假设有一个扩展包含一个叫config.json的JSON配置文件,该文件位于config_resources目录, 那么该扩展能够使用下面这段代码获取文件内容:
```
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = handleStateChange; // Implemented elsewhere.
xhr.open("GET", chrome.extension.getURL('/config_resources/config.json'), true);
xhr.send();
```
如果某个扩展希望访问自己所属域以外的资源,比如说来自http://www.google.com的资源(假设该扩展不是来自www.google.com), 浏览器不会允许这样的请求,除非该扩展获得了相应的跨域请求允许。
## 获取跨域请求允许
通过添加域名或者域名匹配到[manifest](manifest.html)文件的[permissions](manifest.html#permissions_)段, 该扩展就拥有了访问除了自己所属域以外的其他域的访问权限.
```
{
"name": "My extension",
...
**"permissions": [
"http://www.google.com/"
]**,
...
}
```
跨域允许设置可以使用完整域名, 例如:
* "http://www.google.com/"
* "http://www.gmail.com/"
或者使用模式匹配, 例如:
* "http://*.google.com/"
* "http://*/"
模式匹配"http://*/" 表示可以发起到所有域的HTTP请求. 注意在这里, 模式匹配有点像[内容脚本匹配](match_patterns.html), 但是这里的任何域名后的路径信息都被忽略
这里还需要注意访问权限是根据访问协议(匹配模式里的http或者https或者其他协议名)及域名来授予的. 例如某个扩展希望同时基于https和http协议访问某个域或者某些域, 那么它必须分别获取基于这两种协议的访问允许(类似下面这样的声明):
```
"permissions": [
"http://www.google.com/",
"https://www.google.com/"
]
```
## 安全性考虑
每当使用通过XMLHttpRequest获取的资源时, 你编写的背景页需要注意不要成为[跨域脚本](http://en.wikipedia.org/wiki/Cross-site_scripting)的牺牲品. 特别注意避免使用像下面这样的危险API:
```
background.html
===============
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// 警告! 这里有可能执行了一段恶意脚本!
var resp = eval("(" + xhr.responseText + ")");
...
}
}
xhr.send();
background.html
===============
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// 警告! 这样处理有可能被注入恶意脚本!
document.getElementById("resp").innerHTML = xhr.responseText;
...
}
}
xhr.send();
```
实际上我们应该首选不会执行脚本的安全API:
```
background.html
===============
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// JSON解析器不会执行攻击者设计的脚本.
var resp = JSON.parse(xhr.responseText);
}
}
xhr.send();
background.html
===============
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// innerText不会给攻击者注入HTML元素的机会.
document.getElementById("resp").innerText = xhr.responseText;
}
}
xhr.send();
```
另外在使用通过协议HTTP获取的资源时要特别小心. 如果你开发的扩展被应用在恶意网络环境中,网络攻击者(又叫 ["中间人攻击"](http://en.wikipedia.org/wiki/Man-in-the-middle_attack)) 可能篡改服务器响应内容从而可能攻击你编写的扩展. 事实上,你应该尽可能地首选使用HTTPS协议.
- 基础文档
- 综述
- 调试
- 格式:Manifest文件
- 模式匹配
- 改变浏览器外观
- Browser Actions
- Context Menus
- 桌面通知
- Omnibox
- Override替代页
- Page Actions
- 主题
- 与浏览器交互
- 书签
- Cookies
- chrome.devtools.* APIs
- Events
- chrome.history
- Management
- 标签
- 视窗
- 实现扩展
- 无障碍性(a11y)
- 背景页
- Content Scripts
- 跨域 XMLHttpRequest 请求
- 国际化 (i18n)
- 消息传递
- Optional Permissions
- NPAPI 插件
- 完成并发布应用
- 自动升级
- 托管
- 打包
- 规范和协议
- 应用设计规范
- 开发人员协议
- 免责声明