从 Apache 返回空响应

Posted

技术标签:

【中文标题】从 Apache 返回空响应【英文标题】:Return empty response from Apache 【发布时间】:2015-02-26 12:35:50 【问题描述】:

我正在使用 Apache 返回 CORS 响应以加快请求速度(以前我在应用程序代码中处理过这个问题,但这太慢了)。在我的 VirtualHost 中,我有以下 Apache 代码:

SetEnvIfNoCase Access-Control-Request-Method "(GET|POST|PUT|DELETE|OPTIONS)" IsPreflight=1
SetEnvIfNoCase Origin "http(s)?://(myorigin.com)$" AccessControlAllowOrigin=$0$1

Header always set Access-Control-Allow-Origin %AccessControlAllowOrigine env=AccessControlAllowOrigin
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" env=IsPreflight
Header always set Access-Control-Allow-Headers "Content-Type, Authorization, Accept" env=IsPreflight
Header always set Access-Control-Max-Age "7200" env=IsPreflight

RewriteEngine On   
RewriteCond %REQUEST_METHOD OPTIONS
RewriteCond %ENV:IsPreflight 1
RewriteRule ^(.*)$ $1 [R=200,L]

这实际上非常有效。它检测请求是否是预检请求,如果是,则发送适当的标头。只有一个问题:预检请求返回 200(所以浏览器发送正常请求),但正文是 200 ERROR(哈哈):

<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>200 OK</title>
</head><body>
<h1>OK</h1>
<p>The server encountered an internal error or
misconfiguration and was unable to complete
your request.</p>
<p>Please contact the server administrator at 
 you@example.com to inform them of the time this error occurred,
 and the actions you performed just before this error.</p>
<p>More information about this error may be available
in the server error log.</p>
</body></html>

虽然这可以正常工作,但我想从预检正文中删除这个丑陋的错误,但我没有找到任何方法告诉 Apache 实际上返回一个空正文。

谢谢!

【问题讨论】:

你找到解决这个问题的方法了吗?? 【参考方案1】:

使用 204 代码(无内容)响应 OPTIONS 请求。

例如:

RewriteCond %REQUEST_METHOD OPTIONS
RewriteRule ^(.*)$ $1 [R=204,L]

【讨论】:

值得指出的是,返回 204 可能存在浏览器兼容性问题 - 例如 Firefox:***.com/a/58794243/514192【参考方案2】:

204 应该足以满足 CORS 限制。但是,在其他情况下,可能需要具有不同状态代码的空响应。

TL;DR

警告:ErrorDocument 带有 2xx 和 3xx 是未记录的行为。

要发送带有空正文的响应,请将RewriteRuleErrorDocument 组合在一起。

# for 2xx, 4xx, 5xx, with or without flag [L]
RewriteRule ^ - [R=code,L]

# for 3xx
RewriteRule pattern substitution [R=code,L]

# for apache 2.4.13 and later
ErrorDocument code %unescape:%00

# for older versions,
# this can't be done without an empty file,
# the closest you can get using only the configuration is
ErrorDocument code " " 

# if you're willing to use an empty file
ErrorDocument code /path/to/empty/file

关于204无内容

RewriteRule with 204 No Content 按预期工作,只是主要浏览器处理它的方式与其他状态代码不同,例如带有空内容的 200 和 301。

如MDN: 204 No Content中指定,

HTTP 204 No Content 成功状态响应代码表示请求已成功,但客户端不需要离开其当前页面

如果你访问一个 URL 并且它返回 204,Firefox 和 Chromium 将像什么都没发生一样,保持页面内容和导航栏中的 URL 不变。

这可能需要也可能不需要。

但是如果你想要和 200 响应一样的效果,内容为空并且关心 Firefox/Chromium/etc,或者想要使用其他 HTTP 状态码,那么 RewriteRule 和 204 不是解决方案。

带有ErrorDocument 的自定义响应正文

我能找到的最接近的返回空响应的方法是return a custom response body using ErrorDocument,然后设置所需的正文内容。

尽管 Apache 的 Custom Error Responses 文档指出:

可以为任何指定为错误条件的 HTTP 状态代码定义自定义错误响应 - 即任何 4xx 或 5xx 状态。

事实证明,ErrorDocument 可以为 2xx 和 3xx 状态码指定自定义响应。

而我们可以使用RewriteRule's [R] flag进入这种状态,让ErrorDocument生效。

然而,这并不是故事的结局,如下面的配置,

ErrorDocument 200 ""

将引发此错误消息,

ErrorDocument takes two arguments, Change responses for HTTP errors

似乎引用的“空字符串”并没有让位给ErrorDocument 指令,Apache 将此配置行解析为带有单个参数的指令。

在阅读 Apache 的 Syntax of the Configuration Files 并在文档中查找“空格”和“引号”后,我找不到对此的令人满意的解释或将空字符串作为参数的任何提示。它只在参数包含空格的情况下提到引号。

深入了解ErrorDocument

正如 Apache 的 Custom Error Responses 所说,

ErrorDocument 指令的语法是:

ErrorDocument <3-digit-code> <action>

操作将被视为:

    要重定向到的本地 URL(如果操作以“/”开头)。 要重定向到的外部 URL(如果操作是有效 URL)。 要显示的文本(如果以上都不是)。如果文本包含多个单词,则必须用引号 (") 括起来。

在 Apache 的 ErrorDocument Directive 中也有提及,

从 2.4.13 开始,expression syntax 可以在指令内部使用以生成动态字符串和 URL。

从 2.4.13 开始,我们应该可以在 ErrorDocument 中使用表达式了。

挖掘表达式

经过一些实验,我发现并非所有表达式都适用于ErrorDocument。但expression's BNF notation中指定的variable可以在ErrorDocument中解释,

variable    ::= "%" varname ""
              | "%" funcname ":" funcargs ""

rebackref 也可能有效,但我不确定如何在 ErrorDocument 中使用它。)

现在我们只需要一些可以计算为空字符串的空变量或函数。

还有一个空字符串表达式,形式为function,

unescape

Unescape %hex 编码字符串,只留下编码斜线;如果找到%00,则返回一个空字符串

所以这里是返回空响应体的解决方案,

ErrorDocument 200 %unescape:%00

更多关于ErrorDocument

为什么首先有问题中提到的非空响应体?

我在 apache 的 ErrorDocument Directive 中找到了这个,

如果出现问题或错误,Apache httpd 可以配置为执行以下四种操作之一,

    输出一个简单的硬编码错误信息 输出自定义消息 内部重定向到本地 URL 路径以处理问题/错误 重定向到外部 URL 以处理问题/错误

由于未指定 200 的错误文档,Apache 决定使用 200 的硬编码错误消息。

有关硬编码错误消息的详细信息不在文档中,必须在源代码中找到。但我想 200 没有这样的错误消息,所以我们有这个内部错误/错误配置的东西。

可以通过以下方式获得与问题中提到的完全相同的响应

ErrorDocument 200 default

由于 Apache 的 ErrorDocument Directive 提到了这一点,

此外,特殊值 default 可用于指定 Apache httpd 的简单硬编码消息。

【讨论】:

以上是关于从 Apache 返回空响应的主要内容,如果未能解决你的问题,请参考以下文章

RestKit 从 JSON 响应返回空值作为“<null>”

为啥 IIS 返回空响应?

为啥 Symfony Mailer 组件返回一个空响应?

React-Apollo Mutation 返回空响应

处理空服务器响应案例

React JS Fetch 返回空响应,但 Postman 没有