7

我最近将我们的服务器从 Rackspace CloudSites(在 Apache/Linux 上运行)迁移到了 Windows Azure 网站。自迁移以来,我们 REST API 上的所有 jQuery AJAX 请求都因 CORS 而开始失败。

我们使用自定义标头,因此 jQuery 在运行实际 API 调用之前发出 Pre-flight HTTP OPTIONS 请求。问题是 OPTIONS 请求似乎没有到达我的 PHP 代码,而是由我似乎无法控制的其他一些实体(显然是 Web 服务器)返回。

几年来我一直在使用以下标头,所以我很确定问题不在 PHP 代码中:

<?php
    $this->output->set_header("Access-Control-Allow-Origin: *");
    $this->output->set_header("Access-Control-Allow-Methods: GET,POST,DELETE,HEAD,PUT,OPTIONS");
    $this->output->set_header("Access-Control-Allow-Headers: X-Olaround-Debug-Mode, Authorization, Accept");
    $this->output->set_header("Access-Control-Expose-Headers: X-Olaround-Debug-Mode, X-Olaround-Request-Start-Timestamp, X-Olaround-Request-End-Timestamp, X-Olaround-Request-Time, X-Olaround-Request-Method, X-Olaround-Request-Result, X-Olaround-Request-Endpoint" );
?>

我猜这个问题是特定于 Azure 网站的,因为代码似乎在我的开发机器(Windows 8 / IIS 8.0)上也能正常工作。我是 Azure(以及一般基于 Windows 的托管)的新手,所以我几乎不知道如何处理和调试这个问题,因为 Azure 网站允许的控制非常少。

4

3 回答 3

15

我决定发布这个问题的完整解决方案,因为已经提供的答案(虽然在技术上是正确的)在这种特殊情况下对我不起作用。诀窍是执行以下操作:

1.<customHeaders><httpProtocol>web.config中添加

就像上面提到的@hcoat 一样,添加system.webServer.httpProtocol.customHeaders是解决问题的第一步(我之前已经自己尝试过,但是没有用)。在此处添加您需要为 CORS 设置的所有自定义标头和 HTTP 方法。

<httpProtocol>
    <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET,POST,DELETE,HEAD,PUT,OPTIONS" />
        <add name="Access-Control-Allow-Headers" value="Origin, X-Olaround-Debug-Mode, Authorization, Accept" />
        <add name="Access-Control-Expose-Headers" value="X-Olaround-Debug-Mode, X-Olaround-Request-Start-Timestamp, X-Olaround-Request-End-Timestamp, X-Olaround-Request-Time, X-Olaround-Request-Method, X-Olaround-Request-Result, X-Olaround-Request-Endpoint" />
    </customHeaders>
</httpProtocol>

2. 覆盖 PHP 的默认处理程序并删除 OPTIONSVerbHandler

下一步(@Bing Han 提供的解决方案)是删除OPTIONSVerbHandlerIIS 中定义的默认值,并设置一个自定义PHP54_via_FastCGI处理程序来接受您的其他 HTTP 方法。默认处理程序仅适用于 GET、POST 和 HEAD 请求。

<handlers>
    <remove name="OPTIONSVerbHandler" />
    <remove name="PHP54_via_FastCGI" />
    <add name="PHP54_via_FastCGI" path="*.php" verb="GET, PUT, POST, DELETE, HEAD, OPTIONS, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK" modules="FastCgiModule" scriptProcessor="D:\Program Files (x86)\PHP\v5.4\php-cgi.exe" resourceType="Either" requireAccess="Script" />
</handlers>

看看这篇文章,了解更多关于内部工作的细节。

3. 删除通过您的应用程序代码设置的所有响应标头

这是导致最多问题的最后一块拼图。由于 IIS 已经添加<customHeaders>,我在上面的问题中共享的 PHP 代码片段正在复制它们。这导致了浏览器级别的问题,这些问题对相同类型的多个标头响应不佳。

web.config解决这个问题的决赛

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Imported Rule 1" stopProcessing="true">
                    <match url="^(.*)$" ignoreCase="false" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{R:1}" pattern="^(dir_path\.php|lolaround|lolaround\.php|app_assets)" ignoreCase="false" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="lolaround.php/{R:1}" />
                </rule>
                <rule name="Imported Rule 2" stopProcessing="true">
                    <match url="lolaround/(.*)" ignoreCase="false" />
                    <action type="Rewrite" url="/lolaround.php/{R:1}" />
                </rule>
            </rules>
        </rewrite>
        <httpProtocol>
            <customHeaders>
                <add name="Access-Control-Allow-Origin" value="*" />
                <add name="Access-Control-Allow-Methods" value="GET,POST,DELETE,HEAD,PUT,OPTIONS" />
                <add name="Access-Control-Allow-Headers" value="Origin, X-Olaround-Debug-Mode, Authorization, Accept" />
                <add name="Access-Control-Expose-Headers" value="X-Olaround-Debug-Mode, X-Olaround-Request-Start-Timestamp, X-Olaround-Request-End-Timestamp, X-Olaround-Request-Time, X-Olaround-Request-Method, X-Olaround-Request-Result, X-Olaround-Request-Endpoint" />
            </customHeaders>
        </httpProtocol>
        <handlers>
            <remove name="OPTIONSVerbHandler" />
            <remove name="PHP54_via_FastCGI" />
            <add name="PHP54_via_FastCGI" path="*.php" verb="GET, PUT, POST, HEAD, OPTIONS, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK" modules="FastCgiModule" scriptProcessor="D:\Program Files (x86)\PHP\v5.4\php-cgi.exe" resourceType="Either" requireAccess="Script" />
        </handlers>
    </system.webServer>
</configuration>

注意:虽然@hcoat 和@Bing Han 的答案在这个问题上都很有用,但我只能将赏金奖励给其中一个。我决定把它交给@Bing Han,因为他的回答让我最接近解决方案(而且我无法从自己的搜索中找到添加自定义 PHP 处理程序的方法)。

更新:我已经编辑了答案以添加对 HTTP DELETE 方法的支持以及原始答案中缺少的方法。

于 2013-09-30T09:56:53.340 回答
7

HTTP OPTIONS 请求失败,因为默认的 PHP-CGI 处理程序不处理 " OPTIONS" 动词。

在文件中添加以下代码web.config将解决该问题。

<configuration>
  <system.webServer>
    <!-- 
      Some other settings 
    -->
    <handlers>
      <remove name="OPTIONSVerbHandler" />
      <remove name="PHP54_via_FastCGI" />
      <add name="PHP54_via_FastCGI" path="*.php" verb="GET,HEAD,POST,OPTIONS" modules="FastCgiModule" scriptProcessor="D:\Program Files (x86)\PHP\v5.4\php-cgi.exe" resourceType="Either" />
    </handlers>
  </system.webServer>
</configuration>

我对此有一篇博文:http: //tekblg.blogspot.sg/2013/09/azure-websites-php-cross-domain-request.html

于 2013-09-30T04:32:56.480 回答
5

在 Windows 服务器上,您不能依赖于 CORS 的 php 标头。您需要web.config在站点根目录或应用程序根目录中创建包含以下内容的内容。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <system.webServer>
   <httpProtocol>
     <customHeaders>
       <add name="Access-Control-Allow-Origin" value="*" />
       <add name="Access-Control-Allow-Methods" value="GET,POST,DELETE,HEAD,PUT,OPTIONS" />
       <add name="Access-Control-Allow-Headers" value="X-Olaround-Debug-Mode, Authorization, Accept" />
       <add name="Access-Control-Expose-Headers" value="X-Olaround-Debug-Mode, X-Olaround-Request-Start-Timestamp, X-Olaround-Request-End-Timestamp, X-Olaround-Request-Time, X-Olaround-Request-Method, X-Olaround-Request-Result, X-Olaround-Request-Endpoint" />
     </customHeaders>
   </httpProtocol>
 </system.webServer>
</configuration>

此过程类似于设置.htaccess文件,关键是您可以在需要的地方创建它,而无需重新配置服务器。

于 2013-09-29T00:22:58.197 回答