【问题标题】:W7 Pro IIS 7.5 overwrites PHP Location: HeaderW7 Pro IIS 7.5 覆盖 PHP Location: Header
【发布时间】:2024-04-28 12:50:01
【问题描述】:

我正在用 PHP 创建一个 RESTful API,但遇到了一个问题。 当客户端向服务器发送数据时,服务器应该返回:

Status code 201 CREATED
Header Location with the location of the new object
Content-Type application/xml

<SomeXmlData></SomeXmlData>

虚拟代码,在我的电脑上产生问题:

<?php
header("Location: http://google.no/",true,201);
header("Content-Type: application/xml;charset=iso-8859-1");

echo "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n";
echo "<Jada></Jada>";
?>

HTTP 结果是

HTTP/1.1 201 Created
Content-Type: text/html; charset=UTF-8
Location: http://google.no/
Server: Microsoft-IIS/7.5
X-Powered-By: PHP/5.4.5
X-Powered-By: ASP.NET
Date: Wed, 22 Aug 2012 13:52:57 GMT
Content-Length: 209

<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found <a HREF="http://google.no/">here</a></body><?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Jada></Jada>

由于位置标头,PHP 会自动添加一些 HTML 代码和 HTML 内容类型到响应中。

因此,我的 api 无法与它的客户端一起使用。

编辑: IIS 7.5 Windows 7 专业版

【问题讨论】:

  • 为什么您的内容类型标头和 XML 声明在字符编码方面存在分歧?
  • 我认为这是你的服务器在做的,而不是 PHP。
  • X-Powered-By: PHP/5.4.5 X-Powered-By: ASP.NET?每次看到与 IIS 相关的东西,都想尖叫着跑过去。
  • 那肯定是 不是 原始 PHP 这样做的。需要更好的诊断和/或更多信息才能回答。
  • 在我的本地服务器上尝试使用 Apache:发送 Location 标头不会生成自动 HTML。但是,应该注意,如果您使用 http://example.com/dir 而不是 http://example.com/dir/ 并输出类似的 HTML,Apache 会报错:IIS 也可能会这样做。

标签: php rest iis http-headers


【解决方案1】:

很抱歉带来坏消息,但请看这里:

Prevent IIS from changing response when Location header is present

编辑:从未找到答案 - 我最终切换到 Apache

而且似乎 IIS 长期以来一直在关注标头:

http://forums.iis.net/t/1158431.aspx

这是 IIS FastCGI 模块中的一个错误。它将在 Windows 7 RTM 中修复。我们还在研究使此修复适用于 IIS 7 的可能方法。

希望如果这些错误是相关的(我希望它们是相关的),如果你现在有 FastCGI,那么下面的修复可以工作。否则,切换到 PHP 非 FastCGI 模块可能也可以,而且可能比使用 Apache 更容易。

http://support.microsoft.com/kb/980363

【讨论】:

  • 谢谢。我最终放弃了,制作了一个 iis 模块来解决这个问题。
  • +1 以获得巧妙的解决方法。 (可以否决微软?)
  • 在 IIS 8.5.9600.16384 / Windows 8.1 中仍然出现问题
【解决方案2】:

解决方案是创建一个 IIS 模块,在 FastCGI 完成后将标题“Custom-Location”重写为“Location”。

那么,FastCGI 根本不会知道我们正在发送 Location 标头,也不会修改我的响应。

模块:

string Location = context.Response.Headers["Custom-Location"] as string;
if (!string.IsNullOrEmpty(Location))
{
    context.Response.Headers.Remove("Custom-Location");
    context.Response.AddHeader("Location", Location);
}

PHP:

header("Custom-Location: http://google.no",true,201);
header("Content-Type: application/xml");
echo "<xml></xml>";

(仍然是伪代码,不是非常正确的代码:))

【讨论】:

  • 我想澄清一下。这都是关于处理程序而不是模块的。当 IIS 在内容中添加一些 HTML 时,我们遇到了同样的问题。另一个有趣但不明显的事情是,您仍然可以为部署在 IIS 上的 PHP 环境创建托管处理程序。它与创建用托管代码编写的任何其他 http 处理程序相同。
  • 我不明白这里发生了什么。您能解释一下这如何解决 iis 中的问题吗?
  • 问题在于,当存在 Location 标头时,IIS 处理程序正在修改 HTTP 响应正文。我们的解决方案是改为发送“自定义位置”,然后 IIS 处理程序不会对此做任何事情。然后,我制作了一个 IIS 模块,将“Custom-Location”标头重写为“Location”——此逻辑在处理程序逻辑之后,因此处理程序不会修改响应正文。
  • 这个答案已经有四年了,我们不再使用 IIS,所以我不知道这是否仍然有效。
【解决方案3】:

我在 IIS 8.5 上使用 WP REST API 时遇到了类似的问题。关注html

<head>
    <title>Document Moved</title>
</head>
<body>
    <h1>Object Moved</h1>
    This document may be found 
    <a HREF="[url-from-location-header]">here</a>
</body>

在每个返回的带有Location 标头和状态201 Created 的json 的开头添加。 Content-Type 已更改为 text/html; charset=UTF-8

在 php.ini 中添加 cgi.rfc2616_headers = 1 会导致:

  • 没有添加 html 的干净正文 (json)
  • 正确的“内容类型”
  • “位置”标头缺失
  • 状态更改为200 OK

我不会称之为解决方案,这更像是用另一个问题代替一个问题。幸运的是,在我的情况下,这个新问题比原来的问题要小。

【讨论】:

  • 我在 IIS 上使用 flask-restless api (python) 遇到了这个问题。您能否更详细地解释一下您是如何使用 iis 解决问题的?
  • 在我看来,强制 rfc2616 标头不是一个有效的解决方案,因为许多 PHP 应用程序依赖于 apache 标头,例如WordPress。
  • 您还记得您在 Location 标头中返回的是相对 URL (/a/b/c...) 还是绝对 URL (https://...)?
【解决方案4】:

要规避这种 IIS 行为,您可以使用出站重写规则。下面将查找状态 201,如果是,则消除所有内容行,包括结束 body 标签:

<outboundRules>
  <rule name="Remove injected 201 content" preCondition="Status 201">
    <match filterByTags="None" pattern="^(?:.*[\r\n]*)*.*&lt;/body>" />
    <action type="Rewrite" value="" />
  </rule>
  <preConditions>
   <preCondition name="Status 201" patternSyntax="Wildcard">
     <add input="{RESPONSE_STATUS}" pattern="201" ignoreCase="false" />
   </preCondition>
  </preConditions>
</outboundRules>

【讨论】: