diff options
Diffstat (limited to 'files/zh-cn/conflicting/web/http/cors/index.html')
-rw-r--r-- | files/zh-cn/conflicting/web/http/cors/index.html | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/files/zh-cn/conflicting/web/http/cors/index.html b/files/zh-cn/conflicting/web/http/cors/index.html new file mode 100644 index 0000000000..eb37a40e1d --- /dev/null +++ b/files/zh-cn/conflicting/web/http/cors/index.html @@ -0,0 +1,250 @@ +--- +title: Server-Side Access Control +slug: conflicting/Web/HTTP/CORS +tags: + - AJAX + - CORS + - HTTP + - PHP +translation_of: Web/HTTP/CORS +translation_of_original: Web/HTTP/Server-Side_Access_Control +original_slug: Web/HTTP/Server-Side_Access_Control +--- +<p>{{HTTPSidebar}}</p> + +<p>浏览器会针对从 {{domxref("XMLHttpRequest")}} 或<a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch API</a>中发起的跨网站请求发送特定的<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers">HTTP标头</a>。它还希望看到使用跨站点响应发送回的特定HTTP标头。这些标头的概述,包括启动请求和处理来自服务器的响应的示例JavaScript代码, 以及每个头的讨论,可以在HTTP访问控制(<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS">CORS</a>)文章中找到,应该作为本文的配套文章阅读。</p> + +<p>HTTP访问控制文章是很好的使用指南。本文介绍利用PHP处理访问控制请求和制定访问控制响应。本文的目标读者是服务器程序员或管理员。虽然在PHP代码示例所示,类似的概念适用于ASP.net,Perl、Python、Java等;一般来说,这些概念可以应用于任何服务器端编程环境处理HTTP请求和动态制定的HTTP响应。</p> + +<h3 id="讨论HTTP标头"><strong>讨论HTTP标头</strong></h3> + +<p>了解HTTP 头部信息, 建议先阅读这篇文章 <a href="https://developer.mozilla.org/En/HTTP_access_control">covering the HTTP headers used by both clients (such as Firefox 3.5 and beyond) and servers</a></p> + +<div> </div> + +<h3 id="工作代码示例"><strong>工作代码示例</strong></h3> + +<p>随后的章节中PHP代码(和JavaScript调用服务器)可查看<a href="http://arunranga.com/examples/access-control/">相关代码</a>,这些代码在实现了XMLHttpRequest的浏览器上都可运行,像Firefox 3.5及以上。</p> + +<div> </div> + +<h3 id="简单的跨站请求"><strong>简单的跨站请求</strong></h3> + +<p><a class="internal" href="/En/HTTP_access_control#Simple_requests" title="En/HTTP access control#Simple requests">简单的访问控制请求</a> 在下列情况下会被发起:</p> + +<ul> + <li>请求方式为 HTTP/1.1 <code style="font-style: normal;">GET </code>或者<code style="font-style: normal;"> POST</code>,如果是<code style="font-style: normal;">POST</code>,则请求的Content-Type为以下之一: <code style="font-style: normal;">application/x-www-form-urlencoded</code>, <code style="font-style: normal;">multipart/form-data</code>, 或<code style="font-style: normal;">text/plain</code></li> + <li>在请求中,不会发送自定义的头部(如X-Modified)</li> +</ul> + +<p>以下情况,请求会返回相关响应信息</p> + +<ul> + <li>如果资源是允许公开访问的(就像任何允许GET访问的 HTTP资源),返回Access-Control-Allow-Origin:*头信息就足够了,除非是一些需要Cookies和HTTP身份验证信息的请求。</li> + <li> + <div class="tran-result">如果资源访问被限制基于相同的域名,或者如果要访问的资源需要凭证(或设置凭证),那么就有必要对请求头信息中的ORIGIN进行过滤,或者至少响应请求的来源(例如Access-Control-Allow-Origin:http://arunranga.com)。另外,将发送Access-Control-Allow-Credentials:TRUE头信息,这在后续部分将进行讨论。</div> + </li> +</ul> + +<p> <a class="internal" href="/En/HTTP_access_control#Simple_requests" title="En/HTTP access control#Simple requests">简单的访问控制请求</a> 介绍了在客户端和服务端进行信息交换的HEADER. 下面是一段用来处理简单请求的PHP代码。</p> + +<pre class="brush: php"><?php + +// 我们将只授予 arunranga.com 域的访问权限,因为我们认为它通过 application/xml 方式来访问这些资源是安全的。 + +if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com") +{ + + header('Access-Control-Allow-Origin: http://arunranga.com'); + header('Content-type: application/xml'); + readfile('arunerDotNetResource.xml'); +} +else +{ +header('Content-Type: text/html'); +echo "<html>"; +echo "<head>"; +echo " <title>Another Resource</title>"; +echo "</head>"; +echo "<body>", + "<p>This resource behaves two-fold:"; +echo "<ul>", + "<li>If accessed from <code>http://arunranga.com</code> it returns an XML document</li>"; +echo " <li>If accessed from any other origin including from simply typing in the URL into the browser's address bar,"; +echo "you get this HTML document</li>", + "</ul>", +"</body>", +"</html>"; +} +?> +</pre> + +<p>上面的代码通过检查浏览器发送的 <code>ORIGIN</code> 头部信息(通过<code> $_SERVER['HTTP_ORIGIN']</code> ) 是否匹配 '<a class="external" href="http://arunranga.com" rel="freelink" style="font-size: 14px; line-height: 1.5;">http://arunranga.com</a>' 得知,如果是,返回 Access-Control-Allow-Origin: <a class="external" href="http://arunranga.com" rel="freelink" style='font-size: 14px; line-height: 1.5; font-family: "Courier New","Andale Mono",monospace;'>http://arunranga.com</a> 。如果你的浏览器支持访问控制<span style="font-size: 14px; line-height: 1.5;">,你可以访问 <a class="external" href="http://arunranga.com/examples/access-control/" style="font-size: 14px; line-height: 1.5;" title="http://arunranga.com/examples/access-control/">这里 .</a></span></p> + +<h3 id="预请求"><strong>预请求</strong></h3> + +<p><a class="internal" href="/En/HTTP_access_control#Preflighted_requests" title="En/HTTP access control#Preflighted requests">预请求</a> 发生在下列情况中:</p> + +<ul> + <li>使用GET或POST以外的方法;利用POST发送<code style="font-style: normal;">application/x-www-form-urlencoded</code>, <code style="font-style: normal;">multipart/form-data</code>, or <code style="font-style: normal;">text/plain</code>之外的Content-Type;例如,post body的Content-type为<code style="font-style: normal;">application/xml</code></li> + <li>发送自定义的头信息,如x-pingaruner</li> +</ul> + +<p><a class="internal" href="/En/HTTP_access_control#Preflighted_requests" title="En/HTTP access control#Preflighted requests">预请求访问控制</a> 这篇文章介绍了在客户端和服务器间进行交换的<span style="font-size: 14px; line-height: 1.5;">头信息,响应preflight requests请求的服务器资源会有这些动作:</span></p> + +<ul> + <li> 基于 <code>ORIGIN </code>进行过滤</li> + <li> preflight请求的响应内容,包括必要的 <code>Access-Control-Allow-Methods</code>, <code>Access-Control-Allow-Headers</code> (保证系统正常运行),如果需要凭据的话,也会包括 <code>Access-Control-Allow-Credentials </code>头信息</li> + <li>响应实际请求,包括处理 POST数据等。</li> +</ul> + +<p>下面是相关的PHP内容, <a class="internal" href="/En/HTTP_access_control#Preflighted_requests" title="En/HTTP access control#Preflighted requests">preflighted request</a>:</p> + +<pre class="brush: php"><?php +if($_SERVER['REQUEST_METHOD'] == "GET") +{ + header('Content-Type: text/plain'); + echo "This HTTP resource is designed to handle POSTed XML input from arunranga.com and not be retrieved with GET"; + +} +elseif($_SERVER['REQUEST_METHOD'] == "OPTIONS") +{ + // 告诉客户端我们支持来自 arunranga.com 的请求并且预请求有效期将仅有20天 + if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com") + { + header('Access-Control-Allow-Origin: http://arunranga.com'); + header('Access-Control-Allow-Methods: POST, GET, OPTIONS'); + header('Access-Control-Allow-Headers: X-PINGARUNER'); + header('Access-Control-Max-Age: 1728000'); + header("Content-Length: 0"); + header("Content-Type: text/plain"); + //exit(0); + } + else + { + header("HTTP/1.1 403 Access Forbidden"); + header("Content-Type: text/plain"); + echo "You cannot repeat this request"; + + } +} +elseif($_SERVER['REQUEST_METHOD'] == "POST") +{ + /* 通过首先获得XML传送过来的blob来处理POST请求,然后做一些处理, 最后将结果返回客户端 + */ + if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com") + { + $postData = file_get_contents('php://input'); + $document = simplexml_load_string($postData); + + // 对POST过来的数据进行一些处理 + + $ping = $_SERVER['HTTP_X_PINGARUNER']; + + + header('Access-Control-Allow-Origin: http://arunranga.com'); + header('Content-Type: text/plain'); + echo // 处理之后的一些响应 + } + else + die("POSTing Only Allowed from arunranga.com"); +} +else + die("No Other Methods Allowed"); + +?> +</pre> + +<p>可以看到,就像POST一样,针对OPTIONS preflight请求,同样返回对应的头信息。这样 以来,处理preflight就像处理普通的request请求一样,在针对OPTIONS请求的响应信息中,服务器通过客户端,实际的请求可以用POST的形式发送,同时可附加X-PINGARUNERP这样的头信息。如果浏览器支持的话,可访问<a class="external" href="http://arunranga.com/examples/access-control/" style="line-height: 1.5;" title="http://arunranga.com/examples/access-control/"> 这里</a></p> + +<h3 id="凭证请求"><strong>凭证请求</strong></h3> + +<p>带凭据的请求,将Cookies和HTTP认证信息一起发送出去的跨域请求,根据请求方式,可以是<span style="line-height: 1.5;"> </span><a class="internal" href="/En/HTTP_access_control#Simple_requests" style="line-height: 1.5;" title="En/HTTP access control#Simple requests">Simple</a><span style="line-height: 1.5;"> 或 </span><a class="internal" href="/En/HTTP_access_control#Preflighted_requests" style="line-height: 1.5;" title="En/HTTP access control#Preflighted requests">Preflighted</a><span style="line-height: 1.5;">,</span></p> + +<p>发送 <a class="internal" href="/En/HTTP_access_control#Simple%20requests" title="En/HTTP access control#Simple requests">简单请求</a> 时, Firefox 3.5 (或以上)会发送带Cookies信息的请求, (如果<code>withCredentials</code> 设以true). 如果服务器响应真的是可信任的, 客户端接受并进行输出。 在 <a class="internal" href="/En/HTTP_access_control#Preflighted%20requests" title="En/HTTP access control#Preflighted requests">预请求</a> 中,服务器可以<span style="line-height: 1.5;">针对</span><span style="line-height: 1.5;"> </span><code style="font-style: normal; line-height: 1.5;">OPTIONS</code><span style="line-height: 1.5;"> 请求,返回</span><span style="line-height: 1.5;"> </span><code style="font-style: normal; line-height: 1.5;">Access-Control-Allow-Credentials: true</code><span style="line-height: 1.5;"> 信息</span></p> + +<p>下面是处理请求的PHP内容:</p> + +<pre class="brush: php"><?php + +if($_SERVER['REQUEST_METHOD'] == "GET") +{ + + // First See if There Is a Cookie + //$pageAccess = $_COOKIE['pageAccess']; + if (!isset($_COOKIE["pageAccess"])) { + + setcookie("pageAccess", 1, time()+2592000); + header('Access-Control-Allow-Origin: http://arunranga.com'); + header('Cache-Control: no-cache'); + header('Pragma: no-cache'); + header('Access-Control-Allow-Credentials: true'); + header('Content-Type: text/plain'); + echo 'I do not know you or anyone like you so I am going to mark you with a Cookie :-)'; + + } + else + { + + $accesses = $_COOKIE['pageAccess']; + setcookie('pageAccess', ++$accesses, time()+2592000); + header('Access-Control-Allow-Origin: http://arunranga.com'); + header('Access-Control-Allow-Credentials: true'); + header('Cache-Control: no-cache'); + header('Pragma: no-cache'); + header('Content-Type: text/plain'); + echo 'Hello -- I know you or something a lot like you! You have been to ', $_SERVER['SERVER_NAME'], ' at least ', $accesses-1, ' time(s) before!'; + } + +} +elseif($_SERVER['REQUEST_METHOD'] == "OPTIONS") +{ + // Tell the Client this preflight holds good for only 20 days + if($_SERVER['HTTP_ORIGIN'] == "http://arunranga.com") + { + header('Access-Control-Allow-Origin: http://arunranga.com'); + header('Access-Control-Allow-Methods: GET, OPTIONS'); + header('Access-Control-Allow-Credentials: true'); + header('Access-Control-Max-Age: 1728000'); + header("Content-Length: 0"); + header("Content-Type: text/plain"); + //exit(0); + } + else + { + header("HTTP/1.1 403 Access Forbidden"); + header("Content-Type: text/plain"); + echo "You cannot repeat this request"; + + } +} +else + die("This HTTP Resource can ONLY be accessed with GET or OPTIONS"); + + + +?> +</pre> + +<p>需要注意的是,在带凭据请求中, <code>Access-Control-Allow-Origin:</code> 头不能是通配符 "*",必须是一个有效的域名。 可参考这里 <a class="external" href="http://arunranga.com/examples/access-control/" title="http://arunranga.com/examples/access-control/">running here</a></p> + +<h3 id="Apache示例"><strong>Apache示例</strong></h3> + +<h4 id="限制对某些URI的访问"><strong>限制对某些URI的访问</strong></h4> + +<p>最有效的方法之一,利用Apache rewrite, 环境变量,还有headers使<code style="font-style: normal; line-height: 1.5;">Access-Control-Allow-*</code><span style="line-height: 1.5;"> 对某些特定的URI生效,比如,以无认证信息形式利用GET跨域请求api(.*).json。</span></p> + +<pre>RewriteRule ^/api(.*)\.json$ /api$1.json [CORS=True] +Header set Access-Control-Allow-Origin "*" env=CORS +Header set Access-Control-Allow-Methods "GET" env=CORS +Header set Access-Control-Allow-Credentials "false" env=CORS +</pre> + +<h3 id="参见"><strong>参见</strong></h3> + +<ul> + <li><a class="external" href="http://arunranga.com/examples/access-control/" title="http://arunranga.com/examples/access-control/">Examples of Access Control in Action</a></li> + <li><a class="internal" href="/En/HTTP_access_control" title="En/HTTP Access Control">HTTP Access Control covering the HTTP Headers</a></li> + <li><a class="internal" href="/en/DOM/XMLHttpRequest" title="En/XMLHttpRequest">XMLHttpRequest</a></li> + <li><a class="external" href="http://www.webfonts.info/wiki/index.php?title=%40font-face_support_in_Firefox" title="http://www.webfonts.info/wiki/index.php?title=@font-face_support_in_Firefox">Web Fonts</a></li> +</ul> |