http-enc-res-hdr.lua 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. -- 功能:编码 HTTP 返回头
  2. -- 阶段:header_filter_by_lua
  3. -- 备注:
  4. -- aceh = HTTP 返回头的 access-control-expose-headers 字段
  5. -- 无论浏览器是否支持,aceh 始终包含 *
  6. local expose = '*'
  7. -- 该值为 true 表示浏览器不支持 aceh: *,需返回详细的头部列表
  8. local detail = ngx.ctx._acehOld
  9. -- 由于接口路径固定,为避免被缓存,以请求头的 --url 值区分缓存
  10. local vary = '--url'
  11. local function addHdr(k, v)
  12. ngx.header[k] = v
  13. if detail then
  14. expose = expose .. ',' .. k
  15. end
  16. end
  17. local function flushHdr()
  18. if detail then
  19. if status ~= 200 then
  20. expose = expose .. ',--s'
  21. end
  22. -- 该字段不在 aceh 中,如果浏览器能读取到,说明支持 * 通配
  23. ngx.header['--t'] = '1'
  24. end
  25. ngx.header['access-control-expose-headers'] = expose
  26. ngx.header['access-control-allow-origin'] = '*'
  27. ngx.header['vary'] = vary
  28. local status = ngx.status
  29. -- 前端优先使用该字段作为状态码
  30. if status ~= 200 then
  31. ngx.header['--s'] = status
  32. end
  33. -- 保留原始状态码,便于控制台调试
  34. -- 例如 404 显示红色,如果统一设置成 200 则没有颜色区分
  35. -- 需要转义 30X 重定向,否则不符合 cors 标准
  36. if
  37. status == 301 or
  38. status == 302 or
  39. status == 303 or
  40. status == 307 or
  41. status == 308
  42. then
  43. status = status + 10
  44. end
  45. ngx.status = status
  46. end
  47. local function addVary(v)
  48. if type(v) == 'table' then
  49. vary = vary .. ',' .. table.concat(v, ',')
  50. else
  51. vary = vary .. ',' .. v
  52. end
  53. end
  54. local function nodeSwitched()
  55. local status = ngx.status
  56. if status ~= 200 and status ~= 206 then
  57. return false
  58. end
  59. local level = ngx.ctx._level
  60. if level == nil or level == 0 then
  61. return false
  62. end
  63. if ngx.req.get_method() ~= 'GET' then
  64. return false
  65. end
  66. if ngx.header['set-cookie'] ~= nil then
  67. return false
  68. end
  69. local resLenStr = ngx.header['content-length']
  70. if resLenStr == nil then
  71. return false
  72. end
  73. -- 小于 400KB 的资源不走加速
  74. local resLenNum = tonumber(resLenStr)
  75. if resLenNum == nil or resLenNum < 1000 * 400 then
  76. return false
  77. end
  78. local addr = ngx.var.upstream_addr or ''
  79. local etag = ngx.header['etag'] or ''
  80. local last = ngx.header['last-modified'] or ''
  81. local info = addr .. '|' .. resLenStr .. '|' .. etag .. '|' .. last
  82. -- clear all res headers
  83. local h, err = ngx.resp.get_headers()
  84. for k, v in pairs(h) do
  85. ngx.header[k] = nil
  86. end
  87. addHdr('--raw-info', info)
  88. addHdr('--switched', '1')
  89. ngx.header['cache-control'] = 'no-cache'
  90. ngx.var._switched = resLenStr
  91. ngx.ctx._switched = true
  92. flushHdr()
  93. return true
  94. end
  95. -- 节点切换功能,目前还在测试中(demo 中已开启)
  96. if nodeSwitched() then
  97. return
  98. end
  99. local h, err = ngx.resp.get_headers()
  100. for k, v in pairs(h) do
  101. if
  102. -- 这些头有特殊意义,需要转义 --
  103. k == 'access-control-allow-origin' or
  104. k == 'access-control-expose-headers' or
  105. k == 'location' or
  106. k == 'set-cookie'
  107. then
  108. if type(v) == 'table' then
  109. -- 重复的字段,例如 Set-Cookie
  110. -- 转换成 1-Set-Cookie, 2-Set-Cookie, ...
  111. for i = 1, #v do
  112. addHdr(i .. '-' .. k, v[i])
  113. end
  114. else
  115. addHdr('--' .. k, v)
  116. end
  117. ngx.header[k] = nil
  118. elseif k == 'vary' then
  119. addVary(v)
  120. elseif detail and
  121. -- 非简单头无法被 fetch 读取,需添加到 aceh 列表 --
  122. -- https://developer.mozilla.org/en-US/docs/Glossary/Simple_response_header
  123. k ~= 'cache-control' and
  124. k ~= 'content-language' and
  125. k ~= 'content-type' and
  126. k ~= 'expires' and
  127. k ~= 'last-modified' and
  128. k ~= 'pragma'
  129. then
  130. expose = expose .. ',' .. k
  131. end
  132. end
  133. flushHdr()