如何从Nginx中发出相对URL重定向?

31

如何在nginx中配置重定向以响应特定路径的相对重定向?

nginx文档建议这是nginx的默认模式,但实际上,如果被重定向的位置以/开头,nginx会在Location字段中使用绝对URL进行响应。

对于包含位置信息的本地服务器配置:

location = /a {
  return 301 some/path;
}
location = /b {
  return 301 /qwerty;
}

对于请求 /a,响应的位置是:

Location: some/path

而对于 /b 来说,它是:
Location: http://127.0.0.1/qwerty

然而,我们希望/b做出回应:

Location: /qwerty

我们希望使用相对重定向的原因是,我们想从不同的域和代理访问nginx,例如在dev中以明文形式或通过ssl终止负载均衡器,在这种情况下,我们更愿意简化事情,使nginx无需理解上下文。

请注意,这些示例已针对nginx版本1.4.6和1.9.6进行了测试,使用curl进行了测试,例如:

curl --head http://127.0.0.1/b
2个回答

31

nginx版本1.11.8起默认启用了absolute_redirect指令。如果禁用,nginx发出的重定向将是相对的。虽然这个问题有点老了,但对那些从谷歌遇到此问题的人可能仍有用。

 absolute_redirect off;

1
这是最简单和完美的解决方案,但我不得不在一个私人浏览器窗口中检查它,以确认Location头是相对的。由于缓存行为,常规浏览器窗口仍显示绝对位置标头。 - Santhosh

24

如果return uri以 / 开头,nginx头部过滤器会始终插入 <scheme>://<host>
(参考nginx源码中的ngx_http_script_return_code()ngx_http_header_filter()函数)


因此,如果客户端(例如 Google Chrome)可以接受 Location: /qwerty,则可以使用以下配置:

location = /b {
    return 301 " /qwerty";    # insert space char before "/qwerty"
}

通过使用lua-nginx-moduleadd_header指令,另一种解决方案可以准确生成Location: /qwerty:

location = /b {
    add_header Location "/qwerty";
    content_by_lua 'ngx.exit(301)';
}

这个奇怪的配置是如何工作的?

  • 使用ngx.exit以状态码301退出,它不会创建“Location”头部(return指令总是会创建“Location”头部,即使为空头部值)
  • 使用add_header添加Location: /qwerty头部,它不会插入<scheme>://<host>

2
“return”指令中加入空格的技巧不错。这种行为在nginx文档中有记录吗? - Rafał Krypa
2
那个利用空格的技巧很搞笑也很棒,你是怎么发现它的? - Trevor Freeman
嗨@TrevorFreeman,RFC 2616实际上允许“空格技巧”。在“4.2消息头”章节中,标头值被定义为field-value = *(field-content | LWS)* LWS表示零个或多个“线性空格”。 - xiaochen
@xiaochen RFC 2616已经过时3年了。RFC 7231现在允许相对重定向 https://tools.ietf.org/html/rfc7231 - chrkv
add_header解决方案速度明显较慢。 - JJ Roman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接