CORS¶
CORS 是一种机制,允许在浏览器中运行的代码(例如 Javascript)向与代码发起源不同的域发出请求。
Swift 支持对容器和对象进行 CORS 请求。
CORS 元数据仅保存在容器中。给定的值适用于容器本身以及容器内的所有对象。
支持的头部包括:
元数据 |
使用 |
|---|---|
X-Container-Meta-Access-Control-Allow-Origin |
允许进行跨域请求的源,用空格分隔。 |
X-Container-Meta-Access-Control-Max-Age |
源保存预检结果的最长时长。 |
X-Container-Meta-Access-Control-Expose-Headers |
在实际请求响应中暴露给用户代理(例如浏览器)的头部,用空格分隔。 |
除了在容器元数据中设置的值之外,还可以使用 strict_cors_mode、cors_allow_origin 和 cors_expose_headers 在 proxy-server.conf 中配置一些集群范围内的值。有关更多信息,请参阅 proxy-server.conf-sample。
在浏览器发出实际请求之前,它可能会发出一个 预检请求。预检请求是一个 OPTIONS 调用,用于验证源是否允许发出请求。事件顺序如下:
浏览器向 Swift 发出 OPTIONS 请求
Swift 根据允许的源向浏览器返回 200/401
如果返回 200,浏览器将向 Swift 发出“实际请求”,即 PUT、POST、DELETE、HEAD、GET
当浏览器收到实际请求的响应时,它只会暴露 Access-Control-Expose-Headers 头部中列出的头部。默认情况下,Swift 会为该头部返回以下值:
“简单的响应头部”,如 http://www.w3.org/TR/cors/#simple-response-header 上所述
头部
etag、x-timestamp、x-trans-id、x-openstack-request-id所有元数据头部(容器的
X-Container-Meta-*和对象的X-Object-Meta-*)在
X-Container-Meta-Access-Control-Expose-Headers中列出的头部使用
cors_expose_headers选项在proxy-server.conf中配置的头部
注意
对符号链接对象的 OPTIONS 请求将仅响应符号链接的选项,请求不会重定向到目标对象。因此,如果符号链接的目标对象位于具有 CORS 设置的另一个容器中,则响应将不会反映这些设置。
示例 Javascript¶
要查看 CORS Javascript 的实际效果,请下载 测试 CORS 页面(源代码如下)。将其托管在 Web 服务器上,并记下您将用于请求该页面的协议和主机名(源),例如 https://。
找到您想要查询的容器。显而易见的是,托管此容器的 Swift 集群应该具有 CORS 支持。将测试页面的源附加到容器的 X-Container-Meta-Access-Control-Allow-Origin 头部:
curl -X POST -H 'X-Auth-Token: xxx' \
-H 'X-Container-Meta-Access-Control-Allow-Origin: https://' \
http://192.168.56.3:8080/v1/AUTH_test/cont1
此时,容器现在可供托管在 https:// 上的 CORS 客户端访问。在浏览器中打开测试 CORS 页面。
填充 Token 字段
使用容器或对象的 URL 填充 URL 字段
选择请求方法
点击提交
如果请求成功,您应该看到响应头部和主体。如果出现问题,响应状态将为 0。
测试 CORS 页面¶
示例跨站点测试页面位于项目源代码树 doc/source/test-cors.html 中。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test CORS</title>
</head>
<body>
Token<br><input id="token" type="text" size="64"><br><br>
Method<br>
<select id="method">
<option value="GET">GET</option>
<option value="HEAD">HEAD</option>
<option value="POST">POST</option>
<option value="DELETE">DELETE</option>
<option value="PUT">PUT</option>
</select><br><br>
URL (Container or Object)<br><input id="url" size="64" type="text"><br><br>
<input id="submit" type="button" value="Submit" onclick="submit(); return false;">
<pre id="response_headers"></pre>
<p>
<hr>
<pre id="response_body"></pre>
<script type="text/javascript">
function submit() {
var token = document.getElementById('token').value;
var method = document.getElementById('method').value;
var url = document.getElementById('url').value;
document.getElementById('response_headers').textContent = null;
document.getElementById('response_body').textContent = null;
var request = new XMLHttpRequest();
request.onreadystatechange = function (oEvent) {
if (request.readyState == 4) {
responseHeaders = 'Status: ' + request.status;
responseHeaders = responseHeaders + '\nStatus Text: ' + request.statusText;
responseHeaders = responseHeaders + '\n\n' + request.getAllResponseHeaders();
document.getElementById('response_headers').textContent = responseHeaders;
document.getElementById('response_body').textContent = request.responseText;
}
}
request.open(method, url);
if (token != '') {
// custom headers always trigger a pre-flight request
request.setRequestHeader('X-Auth-Token', token);
}
request.send(null);
}
</script>
</body>
</html>