描述

我们配置了一个proxy模式下的nginx,

    upstream backend-test {
server 127.0.0.1:;
}
server {
listen ;
location = /nginx/hwwc/ {
proxy_pass http://backend-test;
proxy_redirect off;
}
location / {
return ;
}
}

访问 http://t103:8080/nginx/hwwc/ 可以正常访问80端口的服务. 访问curl http://t103:8080/nginx/hwwc 的时候, 会返回301重定向. 他们的区别是结尾是否有一个"/"

┬─[tong@T7:~/Src/thirdparty/nginx.git]─[:: PM]
╰─>$ curl http://t103:8080/nginx/hwwc
<html>
<head><title> Moved Permanently</title></head>
<body bgcolor="white">
<center><h1> Moved Permanently</h1></center>
<hr><center>nginx/1.12.</center>
</body>
</html>

结论: 这个问题的原因是, 访问hwwc时触发了nginx的auto_rediect功能. 将请求重定向到了hwwc/

分析过程如下:

调试日志

首先打开nginx的调试.  使用--with-debug选项编译的nginx可以打开此功能, 如下配置:

参考:https://nginx.org/en/docs/ngx_core_module.html#debug_connection

events {
debug_connection 192.168.7.1;
}

在error.log里能看见如下日志: (摘录关键内容)

... ...
2019/09/02 18:37:49 [debug] 23137#0: *70 test location: "/"
2019/09/02 18:37:49 [debug] 23137#0: *70 test location: "nginx/hwwc/"
2019/09/02 18:37:49 [debug] 23137#0: *70 using configuration "=/nginx/hwwc/"
// :: [debug] #: * http cl:- max:
// :: [debug] #: * http finalize request: , "/nginx/hwwc?" a:, c:
// :: [debug] #: * http special response: , "/nginx/hwwc?"
// :: [debug] #: * http set discard body
// :: [debug] #: * xslt filter header
// :: [debug] #: * posix_memalign: 000055830C085F80: @
// :: [debug] #: * HTTP/1.1 Moved Permanently
Server: nginx/1.12.
Date: Mon, Sep :: GMT
Content-Type: text/html
Content-Length:
Location: http://t103:8080/nginx/hwwc/
Connection: keep-alive

通过上边的日志我们能见到, nginx在location"/" 与 "nginx/hwwc/" 中进行选择, 最后选择了"nginx/hwwc/", 然后触发了301.

代码分析

根据上边的日志, 我们通过主要的的关键字"test location" 和 "using configuration" 定位到如下代码:

nginx/src/http/ngx_http_core_module.c::ngx_http_core_find_static_location():1443

        if (len +  == (size_t) node->len && node->auto_redirect) {
r->loc_conf = (node->exact) ? node->exact->loc_conf:
node->inclusive->loc_conf;
rv = NGX_DONE;
}

在location选择的时候, 如果URI字符串比location字符串多了一个字符(也就是"/"),并且前边的字符都相等, 同时node结构体的变量auto_redirect也是true的. 就认为命中了当前location.

也就是说URI"hwwc"会在精确匹配location的检查中匹配到location"hwwc/"

nginx/src/http/ngx_http.c::ngx_http_create_locations_tree():1093

    node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect)
|| (lq->inclusive && lq->inclusive->auto_redirect));

nginx的全局代码中有两个auto_redirect, 一个是(一)中的node结构体. 另一个是config中的结构体.

node中的结构体会通过config中的设置进行赋值. 如该段代码所述.

nginx/src/http/modules/ngx_http_proxy_module.c::ngx_http_proxy_pass():3594

    if (clcf->name.len && clcf->name.data[clcf->name.len - ] == '/') {
clcf->auto_redirect = ;
}

config中的auto_redirect, 当检测到location以"/"结尾的时候, 会自动赋值auto_redirect 为true, 并通过(二)传递到运行时.

这段赋值代码, 除了在proxy模块中, 同时还存在与fastcgi, grpc, memcached, scgi, uwsgi模块中.

nginx/src/http/ngx_http_core_module.h

struct ngx_http_core_loc_conf_s {
... ...
unsigned auto_redirect:;
ngx_flag_t absolute_redirect; /* absolute_redirect */
ngx_flag_t server_name_in_redirect; /* server_name_in_redirect */
ngx_flag_t port_in_redirect; /* port_in_redirect */
... ...
}

nginx/src/http/ngx_http_core_module.c

static ngx_command_t  ngx_http_core_commands[] = {
{ ngx_string("absolute_redirect"),
... ...
{ ngx_string("server_name_in_redirect"),
... ...
{ ngx_string("port_in_redirect"),
... ...
}

分析配置流程中的代码. location中与redirect相关的配置大概一共有四个, 其中auto_redirect是不可配置的. 其他三个可以通过配置文件设置. 但是均与auto_redirect没有逻辑耦合关系.

综上. auto_redirect是不可通过配置修改的. 由URI的结尾是否有"/"自动设置.

如果要改变这一行为,需要进行代码基本的修改。

通过官方文档印证

查看, ngnix的官方文档, 针对该问题有如下的描述,和解决建议. 与我们通过源码进行的分析保持一直:

https://nginx.org/en/docs/http/ngx_http_core_module.html#location

如果, 要屏蔽这个重定向问题, 应该明确的对不带"/"的location进行指定.

另外,

除了以上提到的几个配置, 还有一个proxy_redirect的配置.

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect

通过简单测试,发现当前场景下,该配置并不生效. 应该是由于我们这个场景下个redirect使用proxy发的. 而这个配置项

是针对backend发来的redirect消息进行修改的.

以后可以读一下代码进行确认. 目前先通过测试做这样的黑盒判断.

其他

serverfault上也有人提出同样的问题. 结论与我们的分析一致.

https://serverfault.com/questions/759762/how-to-stop-nginx-301-auto-redirect-when-trailing-slash-is-not-in-uri

最新文章

  1. 分布式理论之一:Paxos算法的通俗理解
  2. Vue学习笔记(一)
  3. SVN版本控制与分支设置
  4. 状态模式(State Pattern)
  5. Java设计模式9:代理模式
  6. ASP.NET MVC 网站开发总结(一)
  7. 仿造slither.io第一步:先画条蛇
  8. 安装GO语言环境之安装Visual Studio Code插件
  9. js中cookie操作
  10. js取单选按钮,复选按钮的值
  11. magento 操作数据库
  12. 解决CentOS虚拟机克隆后无法上网(网卡信息不一致)的问题
  13. 前端性能监控系统 &amp; 前端数据分析系统
  14. AngularJS 入门教程 $http is not defined 解决方案
  15. Shell命令-文件及内容处理之head、tail
  16. cant found Microsoft.VSSDK.BuildTools.15.0.26201
  17. Dispatch Queue 内存结构
  18. win7下iis的配置问题
  19. HDU 3980 Paint Chain (sg函数)
  20. 数值积分:基于牛顿-柯茨公式的定步长和自适应积分方法 [MATLAB]

热门文章

  1. Java3d 案例程序
  2. docker安装并运行redis
  3. [LeetCode] 313. Super Ugly Number 超级丑陋数
  4. 如何在运行时更改JMeter的负载
  5. DS 图解归并排序
  6. 【LEETCODE】56、数组分类,适中级别,题目:62、63、1035
  7. Android--Bitmap处理、圆角、圆形
  8. 记录一次mysql宕机的解决办法
  9. Springboot token令牌验证解决方案 在SpringBoot实现基于Token的用户身份验证
  10. Spring Aop中execution的语法