Nginx return 声明不接受 "text"

Nginx return statement not accepting "text"

以下配置对我有用:

server {
  listen 80;

  root /app/web;
  index index.json;

  location / {
    return 409;
  }
}

如果我点击该网站,将显示 409 页面。但是以下不起作用:

server {
  listen 80;

  root /app/web;
  index index.json;

  location / {
    return 409 "foobar";
  }
}

无法访问该页面。但是根据文档 http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return

return 409 "foobar";

应该可以。任何想法怎么了? nginx/error.log.

中没有日志

事实是,Nginx 完全按照您的要求去做。您可以通过调用 curl -v http://localhost(或您使用的任何主机名)来验证这一点。结果看起来像这样:

* Rebuilt URL to: http://localhost/
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost
> Accept: */*
> 
< HTTP/1.1 409 Conflict
* Server nginx/1.4.6 (Ubuntu) is not blacklisted
< Server: nginx/1.4.6 (Ubuntu)
< Date: Fri, 08 May 2015 19:43:12 GMT
< Content-Type: application/octet-stream
< Content-Length: 6
< Connection: keep-alive
< 
* Connection #0 to host localhost left intact
foobar

如您所见,Nginx return 是 409 和 foobar,正如您所订购的。

所以这里真正的问题是,为什么您的浏览器在 return 代码后没有自定义文本时显示格式漂亮的错误页面,而在存在此类文本时显示灰色 "unreachable" .

答案是:因为 Content-Type header 值。

HTTP 标准声明某些响应代码应该或必须随响应一起提供 body。为了符合标准,Nginx 这样做:每当你 return 一个没有要求的 body 的特殊响应代码时,Web 服务器发送它自己的 hardcoded HTML 响应给客户端.此响应的一部分是 header Content-Type: text/html。这就是为什么当您在没有文本部分的情况下执行 return 409 时会看到漂亮的白色错误页面的原因 — 因此 header 您的浏览器知道 returned 数据是 HTML并将其呈现为 HTML.

另一方面,当您指定 text 部分时,Nginx 不需要发送它自己的 body 版本。所以它只是将您的文本、响应代码和与请求的文件匹配的 Content-Type 的值发送回客户端(参见 /etc/nginx/mime.types)。

当没有文件时,例如当您请求文件夹或站点根目录时,将使用默认的 MIME 类型。而这个MIME类型是application/octet-stream,它定义了一些二进制数据。由于大多数浏览器不知道如何呈现随机二进制数据,因此它们会尽力而为,也就是说,它们会显示自己的硬编码错误页面。

这就是为什么你会得到你所得到的。

现在如果你想让你的浏览器显示你的foobar,你需要发送一个合适的Content-Type。类似于 text/plaintext/html。通常,这可以用 add_header 完成,但在您的情况下不行,因为该指令仅适用于有限的响应代码列表(200、201、204、206、301、302、303、304 或 307 ).

我看到的唯一其他选择是将您的原始请求重写为 Nginx 熟悉的内容,以便它可以将 /etc/nginx/mime.types 中的值用于 Content-Type:

server {
    listen 80;

    root /app/web;
    index index.json;

    location / {
        rewrite ^.*$ /index.html;
        return 409 "foobar";
    }
}

这似乎有点 counter-intuitive 但这会起作用。

编辑:

看来 Content-Type 可以用 default_type 指令设置。所以你可以(并且应该)使用 default_type text/plain; 而不是 rewrite 行。

正在更新@ivan-tsirulev 的回答:

现在 you can set headers 甚至对于使用 always.

错误状态代码的页面
location @custom_error_page {
    return 409 "foobar";
    add_header Content-Type text/plain always;
}

但是如果你设置default_type,响应headers会有两个Content-Type headers:默认,然后添加。尽管如此,它工作正常。