问题描述
我正在尝试构建一个基于Nginx的维护模式应用程序,该应用程序捕获对我的应用程序的所有请求,并以503返回预定义的响应。
我目前有一些请求json响应的应用程序,以及使用浏览器访问页面的用户。因此,如果请求包含标头Accept: application/json
,我想用json文件maintenance.json
的内容来响应,否则要用html文件maintenance.html
来响应。
我当前的Nginx配置如下:
server {
listen 8080;
root /usr/share/Nginx/maintenance;
server_tokens off;
error_page 503 = @unavailable;
location ^~ / {
return 503;
}
location @unavailable {
set $maintenanceContentType text/html;
set $maintenanceFile /maintenance.html;
if ($http_accept = 'application/json') {
set $maintenanceContentType application/json;
set $maintenanceFile /maintenance.json;
}
default_type $maintenanceContentType;
try_files $uri $maintenanceFile;
}
}
对于浏览器对任何路径的请求,都可以正常工作:“ https://maintenance.my-domain.local/some-path”。我得到了响应代码和html内容。
但是对于标题为Accept: application/json
的请求,我会得到一个404 HTML页面。并且Nginx日志显示 [错误] 21#21:* 1 open()“ / usr / share / Nginx / maintenance / some-path”失败(2:无此类文件或目录),客户端:10.244.2.65 ,服务器:,请求:“ GET / asd HTTP / 1.1”,主机:“ maintenance.my-domain.local” 。
由于某种原因,似乎json请求忽略了我的location
。当我删除设置适当文件的指令并始终返回html时,这也适用于 json-requests 。
有人知道吗?
我不一定要为此特定配置寻找修复程序,而是要寻找适合我需要的基于Accept标头响应不同“错误页面”的内容。
谢谢!
编辑:由于某种原因,这现在导致HTTP 200而不是503。不知道我做了什么更改。.
EDIT2:设法修复了其中的一部分:
server {
listen 8080;
root /usr/share/Nginx/maintenance;
server_tokens off;
location ^~ / {
if ($http_accept = 'application/json') {
return 503;
}
try_files /maintenance.html =404;
}
error_page 503 /maintenance.json;
location = /maintenance.json {
internal;
}
}
通过此配置,现在我在定义标题Accept: application/json
时使用浏览器和维护json时获得维护页面。浏览器的响应代码现在为200 ...
解决方法
好的,我找到了解决问题的方法。
# map the incoming Accept header to a file extension
map $http_accept $accept_ext {
default html;
application/json json;
}
server {
listen 8080;
root /usr/share/nginx/maintenance;
server_tokens off;
# return 503 for all incoming requests
location ^~ / {
return 503;
}
# a 503 redirects to the internal location `@maintenance`. the
# extension of the returned file is decided by the Accept header map
# above (404 in case the file is not found).
error_page 503 @maintenance;
location @maintenance {
internal;
try_files /maintenance.$accept_ext =404;
}
}
键是顶部的地图。我只是在此处添加application/json
,并且默认情况下将其他所有内容映射到html文件。但是您当然可以在那里添加多个其他文件/文件类型。