• 04 访问 /staticTryFiles 或者 /staticTryFiles/ 的一些具体行为体现


    前言

    之前曾经做过一个测试, 测试结果如下  

    1. nginx 访问文件
    2. 如果文件存在, 获取文件
    3. 如果文件不存在, 文件夹存在, 获取文件夹的 index
    4. 如果都不存在 响应 403/404

    然后 后面更加详细的测试了一下, 梳理了一下 结论 

    1. 请求 匹配到 /staticTryFiles 的时候, 查找是否有文件, 如果 有文件, 响应文件
    2. 如果没有文件, 有文件夹, 跳转到 /staticTryFiles/, 如果有 index 文件, 响应 index
    3. 如果没有 index 文件, 响应 403
    4. 如果有文件夹, 跳转到 "/staticTryFiles/", 这个的处理是在 ngx_http_static_module.ngx_http_static_handler 中, 响应了一个 sendRedirect "/staticTryFiles/"
    5. 如果没有文件夹, 响应 404
    6. ngx_http_static_module.ngx_http_static_handler 中响应错误码 NGX_HTTP_NOT_FOUND, 外层 ngx_http_core_content_phase 发现错误码不是 NGX_DECLINED, 发送响应给客户端
    7. 请求 匹配到 /staticTryFiles/ 的时候, 如果有 index 文件, 响应 index
    8. 如果没有 index 文件, 响应 403
    9. 这里是所有的 index 尝试完毕之后, 所有的 phase_checker 都处理完成之后
    10. 最后一个 static_handler 的结果依然为 DECLINED, 走的 ngx_http_core_module.ngx_http_core_content_phase 之后响应的 FORBIDDEN
    11. 这个处理是在 ngx_http_index_module 中, 需要确保 r.uri 以 "/" 结尾, 确保 method 为 HEAD/GET/POST
    12. 获取 index 的相关配置, 然后遍历 index 列表
    13. 尝试添加 index 到 uri, 然后尝试 打开文件, 如果 打开没有问题, 直接 内部跳转 获取给定的文件返回
    14. 这个内部跳转是在当前请求的基础上, 更新了 r.uri 之后, 递归走 handler chain
    15. 如果文件存在, 但是存在其他问题, 权限, 文件名过长 响应 相应的错误信息
    16. EMLINK : too many links, 响应 403 - FORBIDDEN
    17. ELOOP : too many symbolic links encountered, 响应 403 - FORBIDDEN
    18. ENOTDIR : not directory, 响应 404 - NOTFOUND
    19. ENAMETOOLONG : file name too long, 响应 404 - NOTFOUND
    20. EACCESS : permission denied, 响应 403 - FORBIDDEN
    21. ENOENT : 如果是 index文件 不存在, 则 continue 下一个 index

    以下截图, 调试基于 nginx-1.18.0

    请求 /staticTryFiles 的相关处理

    根据上下文 uri 以及 root 拼接完整的请求文件路径的地方 

    1. (gdb) list
    2. 72 /*
    3. 73 * ngx_http_map_uri_to_path() allocates memory for terminating '\0'
    4. 74 * so we do not need to reserve memory for '/' for possible redirect
    5. 75 */
    6. 76
    7. 77 last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    8. 78 if (last == NULL) {
    9. 79 return NGX_HTTP_INTERNAL_SERVER_ERROR;
    10. 80 }
    11. 81
    12. (gdb) print r.uri
    13. $4 = {len = 15, data = 0x7ff9f8800004 "/staticTryFiles HTTP/1.1\r\nHost"}
    14. (gdb) print path
    15. $5 = {len = 140711584440536,
    16. data = 0xf801a118 <error: Cannot access memory at address 0xf801a118>}
    17. (gdb) next
    18. 78 if (last == NULL) {
    19. (gdb) print path
    20. $7 = {len = 44,
    21. data = 0x7ff9f8801148 "/usr/local/nginx/html/static/staticTryFiles"}

    case1 文件存在 并且 能够正常打开文件

    直接 响应文件内容给客户端, contentType 的配置参见 nginx 是如何自动推导文件的 content-type 的

    调试查看运行时的信息, 文件为 "/usr/local/nginx/html/static/staticTryFiles", 大小为 25b 

    根据后缀推导 contentType 没有找到合适的, 使用的默认的 application/octet-stream

    1. Breakpoint 3, ngx_http_static_handler (r=0x7ff9f8800450)
    2. at src/http/modules/ngx_http_static_module.c:268
    3. 268 return ngx_http_output_filter(r, &out);
    4. (gdb) print b->file->name
    5. $11 = {len = 43,
    6. data = 0x7ff9f8801148 "/usr/local/nginx/html/static/staticTryFiles"}
    7. (gdb) b->file_pos
    8. Undefined command: "b->file_pos". Try "help".
    9. (gdb) print b->file_pos
    10. $12 = 0
    11. (gdb) print b->file_last
    12. $13 = 25
    13. (gdb) print r->headers_out
    14. $14 = {headers = {last = 0x7ff9f8800638, part = {elts = 0x7ff9f8800a00,
    15. nelts = 2, next = 0x0}, size = 48, nalloc = 20, pool = 0x7ff9f8800400},
    16. trailers = {last = 0x7ff9f8800670, part = {elts = 0x7ff9f8800dc0, nelts = 0,
    17. next = 0x0}, size = 48, nalloc = 4, pool = 0x7ff9f8800400},
    18. status = 200, status_line = {len = 0, data = 0x0}, server = 0x0, date = 0x0,
    19. content_length = 0x0, content_encoding = 0x0, location = 0x0, refresh = 0x0,
    20. last_modified = 0x0, content_range = 0x0, accept_ranges = 0x7ff9f8800a30,
    21. www_authenticate = 0x0, expires = 0x0, etag = 0x7ff9f8800a00,
    22. override_charset = 0x0, content_type_len = 24, content_type = {len = 24,
    23. data = 0x7ff9f8012495 "application/octet-stream"}, charset = {len = 0,
    24. data = 0x0}, content_type_lowcase = 0x0, content_type_hash = 0,
    25. cache_control = {elts = 0x0, nelts = 0, size = 0, nalloc = 0, pool = 0x0},
    26. link = {elts = 0x0, nelts = 0, size = 0, nalloc = 0, pool = 0x0},
    27. content_length_n = 25, content_offset = 0, date_time = 0,
    28. last_modified_time = 1656808030}

    查看一下 html/static/staticTryFiles 的文件大小, 确实为 25b 

    1. master:nginx jerry$ ll html/static/
    2. total 16
    3. -rw-r--r-- 1 jerry wheel 21 Jun 22 22:42 index.html
    4. -rw-r--r-- 1 jerry wheel 25 Jul 3 08:27 staticTryFiles

    浏览器的默认行为为 下载给定的文件 

    case2 没有找到文件, 但是找到文件夹 转发到文件夹 

    如果是存在 staticTryFiles 的文件夹, ngx_open_cached_file 正常 

    然后 走了后面的 staticTryFiles 文件夹的相关操作, 是一个 302 跳转到 "/staticTryFiles/"

    1. Breakpoint 4, ngx_http_static_handler (r=0x7ff9f8009450)
    2. at src/http/modules/ngx_http_static_module.c:102
    3. 102 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
    4. (gdb) next
    5. 103 != NGX_OK)
    6. (gdb) next
    7. 102 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
    8. (gdb) next
    9. 105 switch (of.err) {
    10. (gdb) next
    11. 114 level = NGX_LOG_ERR;
    12. (gdb) next
    13. 115 rc = NGX_HTTP_NOT_FOUND;
    14. (gdb) next
    15. 116 break;
    16. (gdb) next
    17. 135 if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
    18. (gdb) next
    19. 136 ngx_log_error(level, log, of.err,
    20. (gdb) next
    21. 138 }
    22. (gdb) next
    23. 140 return rc;
    24. (gdb) next
    25. 269
    26. (gdb) c
    27. Continuing.
    28. Breakpoint 2, ngx_http_static_handler (r=0x7ff9f9004e50)
    29. at src/http/modules/ngx_http_static_module.c:77
    30. 77 last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    31. (gdb) c
    32. Continuing.
    33. Breakpoint 4, ngx_http_static_handler (r=0x7ff9f9004e50)
    34. at src/http/modules/ngx_http_static_module.c:102
    35. 102 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
    36. (gdb) next
    37. 103 != NGX_OK)
    38. (gdb) next
    39. 102 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
    40. (gdb) next
    41. 143 r->root_tested = !r->error_page;
    42. (gdb) next
    43. 147 if (of.is_dir) {
    44. (gdb) next
    45. 151 ngx_http_clear_location(r);
    46. (gdb) br ngx_http_static_module.c:191
    47. Breakpoint 5 at 0x106b03d3d: file src/http/modules/ngx_http_static_module.c, line 191.
    48. (gdb) c
    49. Continuing.
    50. Breakpoint 5, ngx_http_static_handler (r=0x7ff9f9004e50)
    51. at src/http/modules/ngx_http_static_module.c:191
    52. 191 return NGX_HTTP_MOVED_PERMANENTLY;
    53. (gdb) delete 5
    54. (gdb) print location
    55. $15 = (u_char *) 0x7ff9f9005b64 "/staticTryFiles/"
    56. (gdb) print r.headers_out
    57. $16 = {headers = {last = 0x7ff9f9005038, part = {elts = 0x7ff9f9005400,
    58. nelts = 1, next = 0x0}, size = 48, nalloc = 20, pool = 0x7ff9f9004e00},
    59. trailers = {last = 0x7ff9f9005070, part = {elts = 0x7ff9f90057c0, nelts = 0,
    60. next = 0x0}, size = 48, nalloc = 4, pool = 0x7ff9f9004e00}, status = 0,
    61. status_line = {len = 0, data = 0x0}, server = 0x0, date = 0x0,
    62. content_length = 0x0, content_encoding = 0x0, location = 0x7ff9f9005400,
    63. refresh = 0x0, last_modified = 0x0, content_range = 0x0,
    64. accept_ranges = 0x0, www_authenticate = 0x0, expires = 0x0, etag = 0x0,
    65. override_charset = 0x0, content_type_len = 0, content_type = {len = 0,
    66. data = 0x0}, charset = {len = 0, data = 0x0}, content_type_lowcase = 0x0,
    67. content_type_hash = 0, cache_control = {elts = 0x0, nelts = 0, size = 0,
    68. nalloc = 0, pool = 0x0}, link = {elts = 0x0, nelts = 0, size = 0,
    69. nalloc = 0, pool = 0x0}, content_length_n = -1, content_offset = 0,
    70. date_time = 0, last_modified_time = -1}
    71. (gdb)

    case3 文件 和 文件夹均不存在

    打开文件的时候 发现文件不存在, 响应 404 错误码 

    外部 http_core_content_phase 发送 404 的响应给客户端 

    1. Breakpoint 2, ngx_http_static_handler (r=0x7ff9fa000450)
    2. at src/http/modules/ngx_http_static_module.c:77
    3. 77 last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    4. (gdb) c
    5. Continuing.
    6. Breakpoint 4, ngx_http_static_handler (r=0x7ff9fa000450)
    7. at src/http/modules/ngx_http_static_module.c:102
    8. 102 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
    9. (gdb) next
    10. 103 != NGX_OK)
    11. (gdb) next
    12. 102 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
    13. (gdb) next
    14. 105 switch (of.err) {
    15. (gdb) next
    16. 114 level = NGX_LOG_ERR;
    17. (gdb) next
    18. 115 rc = NGX_HTTP_NOT_FOUND;
    19. (gdb) next
    20. 116 break;
    21. (gdb) next
    22. 135 if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
    23. (gdb) next
    24. 136 ngx_log_error(level, log, of.err,
    25. (gdb) next
    26. 138 }
    27. (gdb) next
    28. 140 return rc;
    29. (gdb) print rc
    30. $19 = 404
    31. (gdb) b ngx_http_core_module.c:1257
    32. Breakpoint 6 at 0x106ab0043: file src/http/ngx_http_core_module.c, line 1257.
    33. (gdb) c
    34. Continuing.
    35. Breakpoint 6, ngx_http_core_content_phase (r=0x7ff9fa000450, ph=0x7ff9f801eb60)
    36. at src/http/ngx_http_core_module.c:1257
    37. warning: Source file is more recent than executable.
    38. 1257 ngx_http_finalize_request(r, rc);
    39. (gdb) print rc
    40. $20 = 404

    请求 /staticTryFiles/ 的相关处理

    case1 存在某一个 index 文件

    这个处理是在 ngx_http_index_module 中, 需要确保 r.uri 以 "/" 结尾, 确保 method 为 HEAD/GET/POST
    获取 index 的相关配置, 然后遍历 index 列表
        尝试添加 index 到 uri, 然后尝试 打开文件, 如果 打开没有问题, 直接 内部跳转 获取给定的文件返回
            这个内部跳转是在当前请求的基础上, 更新了 r.uri 之后, 递归走 handler chain
        如果文件存在, 但是存在其他问题, 权限, 文件名过长 响应 相应的错误信息
            EMLINK : too many links, 响应 403 - FORBIDDEN
            ELOOP : too many symbolic links encountered, 响应 403 - FORBIDDEN
            ENOTDIR : not directory, 响应 404 - NOTFOUND
            ENAMETOOLONG : file name too long, 响应 404 - NOTFOUND
            EACCESS : permission denied, 响应 403 - FORBIDDEN
        ENOENT : 如果是 index文件 不存在, 则 continue 下一个 index
    

    1. Breakpoint 7, ngx_http_index_handler (r=0x7ff9fa000450)
    2. at src/http/modules/ngx_http_index_module.c:130
    3. 130 index = ilcf->indices->elts;
    4. (gdb) next
    5. 131 for (i = 0; i < ilcf->indices->nelts; i++) {
    6. (gdb) next
    7. 133 if (index[i].lengths == NULL) {
    8. (gdb) print index[0]
    9. $24 = {name = {len = 12, data = 0x7ff9f801b05e "index1.html"}, lengths = 0x0,
    10. values = 0x0}
    11. (gdb) print index[1]
    12. $26 = {name = {len = 11, data = 0x7ff9f801b06a "index1.htm"}, lengths = 0x0,
    13. values = 0x0}
    14. (gdb) next
    15. 135 if (index[i].name.data[0] == '/') {
    16. (gdb) next
    17. 139 reserve = ilcf->max_index_len;
    18. (gdb) next
    19. 140 len = index[i].name.len;
    20. (gdb) next
    21. 142 } else {
    22. (gdb) next
    23. 162 if (reserve > allocated) {
    24. (gdb) next
    25. 164 name = ngx_http_map_uri_to_path(r, &path, &root, reserve);
    26. (gdb) next
    27. 165 if (name == NULL) {
    28. (gdb) print name
    29. $27 = (u_char *) 0x7ff9fa001174 ""
    30. (gdb) print path
    31. $28 = {len = 56,
    32. data = 0x7ff9fa001148 "/usr/local/nginx/html/static/staticTryFiles/"}
    33. (gdb) next
    34. 169 allocated = path.data + path.len - name;
    35. (gdb) next
    36. 172 if (index[i].values == NULL) {
    37. (gdb) next
    38. 176 ngx_memcpy(name, index[i].name.data, index[i].name.len);
    39. (gdb) next
    40. 178 path.len = (name + index[i].name.len - 1) - path.data;
    41. (gdb) next
    42. 180 } else {
    43. (gdb) next
    44. 203 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
    45. (gdb) next
    46. 205 of.read_ahead = clcf->read_ahead;
    47. (gdb) next
    48. 206 of.directio = clcf->directio;
    49. (gdb) print name
    50. $29 = (u_char *) 0x7ff9fa001174 "index1.html"
    51. (gdb) print path
    52. $30 = {len = 55,
    53. data = 0x7ff9fa001148 "/usr/local/nginx/html/static/staticTryFiles/index1.html"}
    54. (gdb) next
    55. 207 of.valid = clcf->open_file_cache_valid;
    56. (gdb) next
    57. 208 of.min_uses = clcf->open_file_cache_min_uses;
    58. (gdb) next
    59. 209 of.test_only = 1;
    60. (gdb) next
    61. 210 of.errors = clcf->open_file_cache_errors;
    62. (gdb) next
    63. 211 of.events = clcf->open_file_cache_events;
    64. (gdb) next
    65. 213 if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
    66. (gdb) next
    67. 217 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
    68. (gdb) next
    69. 218 != NGX_OK)
    70. (gdb) next
    71. 217 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
    72. (gdb) next
    73. 262 uri.len = r->uri.len + len - 1;
    74. (gdb) next
    75. 264 if (!clcf->alias) {
    76. (gdb) next
    77. 265 uri.data = path.data + root;
    78. (gdb) next
    79. 267 } else {
    80. (gdb) next
    81. 277 return ngx_http_internal_redirect(r, &uri, &r->args);
    82. (gdb) print uri
    83. $31 = {len = 27, data = 0x7ff9fa001164 "/staticTryFiles/index1.html"}

    case2 所有 index 文件均不存在

    如果所有的 index 文件均不存在, ngx_http_core_content_phase 最后响应一个 HTTP_FORBIDDEN 

    1. Breakpoint 7, ngx_http_index_handler (r=0x7ff9f7810050)
    2. at src/http/modules/ngx_http_index_module.c:130
    3. 130 index = ilcf->indices->elts;
    4. (gdb) b ngx_http_core_module.c:1279
    5. Breakpoint 8 at 0x106ab0129: file src/http/ngx_http_core_module.c, line 1279.
    6. (gdb) c
    7. Continuing.
    8. Breakpoint 8, ngx_http_core_content_phase (r=0x7ff9f7810050, ph=0x7ff9f801eb78)
    9. at src/http/ngx_http_core_module.c:1279
    10. 1279 ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN);
    11. (gdb) list
    12. 1274 if (ngx_http_map_uri_to_path(r, &path, &root, 0) != NULL) {
    13. 1275 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
    14. 1276 "directory index of \"%s\" is forbidden", path.data);
    15. 1277 }
    16. 1278
    17. 1279 ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN);
    18. 1280 return NGX_OK;
    19. 1281 }
    20. 1282
    21. 1283 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no handler found");

    完 

  • 相关阅读:
    webpack之性能优化
    Redis 通信协议 -- RESP
    数学建模学习笔记(10):因子分析法
    从单个/两个向量构建一组正交基底
    java+springboot基于vue中小学生作业管理系统 ssm学习辅助系统
    【ElfBoard】基于 Linux 的智能家居小项目
    DAY-7 | 牛客-BM21 寻找旋转数组的最小元素:二分法分治思想真的很可靠
    Python练习题六
    CodeTON Round 3 (Div. 1 + Div. 2, Rated, Prizes!)——A、B、C
    国际金融学试题及参考答案
  • 原文地址:https://blog.csdn.net/u011039332/article/details/125569244