http-enc-res-hdr.lua 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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. expose = expose .. ',--s'
  20. -- 该字段不在 aceh 中,如果浏览器能读取到,说明支持 * 通配
  21. ngx.header['--t'] = '1'
  22. end
  23. local status = ngx.status
  24. ngx.header['access-control-expose-headers'] = expose
  25. ngx.header['access-control-allow-origin'] = '*'
  26. ngx.header['vary'] = vary
  27. ngx.header['--s'] = status
  28. if
  29. status == 301 or
  30. status == 302 or
  31. status == 303 or
  32. status == 307 or
  33. status == 308
  34. then
  35. status = status + 10
  36. end
  37. ngx.status = status
  38. end
  39. local function addVary(v)
  40. if type(v) == 'table' then
  41. vary = vary .. ',' .. table.concat(v, ',')
  42. else
  43. vary = vary .. ',' .. v
  44. end
  45. end
  46. local function nodeSwitched()
  47. local status = ngx.status
  48. if status ~= 200 and status ~= 206 then
  49. return false
  50. end
  51. local level = ngx.ctx._level
  52. if level == nil or level == 0 then
  53. return false
  54. end
  55. if ngx.req.get_method() ~= 'GET' then
  56. return false
  57. end
  58. if ngx.header['set-cookie'] ~= nil then
  59. return false
  60. end
  61. local resLenStr = ngx.header['content-length']
  62. if resLenStr == nil then
  63. return false
  64. end
  65. -- 小于 400KB 的资源不走加速
  66. local resLenNum = tonumber(resLenStr)
  67. if resLenNum == nil or resLenNum < 1000 * 400 then
  68. return false
  69. end
  70. -- -- cache time
  71. -- local ccStr = ngx.header['cache-control']
  72. -- if ccStr == nil then
  73. -- return false
  74. -- end
  75. -- if type(ccStr) == 'table' then
  76. -- ccStr = table.concat(ccStr, ',')
  77. -- end
  78. -- -- `cache-control: xxxxx, max-age=31536000, xxxxx`
  79. -- local regex = [[(?:^|;\s*)max-age=(\d+)]]
  80. -- local m = ngx.re.match(ccStr, regex, 'oi')
  81. -- if m == nil then
  82. -- return false
  83. -- end
  84. -- local seconds = tonumber(m[1])
  85. -- if seconds == nil then
  86. -- return false
  87. -- end
  88. -- if seconds < 3600 * 24 then
  89. -- return false
  90. -- end
  91. local addr = ngx.var.upstream_addr or ''
  92. local etag = ngx.header['etag'] or ''
  93. local last = ngx.header['last-modified'] or ''
  94. -- TODO: , -> ,,
  95. local info = addr .. ',' .. resLenStr .. ',' .. etag .. ',' .. last
  96. -- clear all res headers
  97. local h, err = ngx.resp.get_headers()
  98. for k, v in pairs(h) do
  99. ngx.header[k] = nil
  100. end
  101. addHdr('--raw-info', info)
  102. addHdr('--switched', '1')
  103. ngx.header['cache-control'] = 'no-cache'
  104. ngx.var._switched = resLenStr
  105. ngx.ctx._switched = true
  106. flushHdr()
  107. return true
  108. end
  109. if nodeSwitched() then
  110. return
  111. end
  112. local h, err = ngx.resp.get_headers()
  113. for k, v in pairs(h) do
  114. if
  115. -- 这些头有特殊意义,需要转义 --
  116. k == 'access-control-allow-origin' or
  117. k == 'access-control-expose-headers' or
  118. k == 'location' or
  119. k == 'set-cookie'
  120. then
  121. if type(v) == 'table' then
  122. -- 重复的字段,例如 Set-Cookie
  123. -- 转换成 1-Set-Cookie, 2-Set-Cookie, ...
  124. for i = 1, #v do
  125. addHdr(i .. '-' .. k, v[i])
  126. end
  127. else
  128. addHdr('--' .. k, v)
  129. end
  130. ngx.header[k] = nil
  131. elseif k == 'vary' then
  132. addVary(v)
  133. elseif detail and
  134. -- 非简单头无法被 fetch 读取,需添加到 aceh 列表 --
  135. -- https://developer.mozilla.org/en-US/docs/Glossary/Simple_response_header
  136. k ~= 'cache-control' and
  137. k ~= 'content-language' and
  138. k ~= 'content-type' and
  139. k ~= 'expires' and
  140. k ~= 'last-modified' and
  141. k ~= 'pragma'
  142. then
  143. expose = expose .. ',' .. k
  144. end
  145. end
  146. flushHdr()