http-enc-res-hdr.lua 3.9 KB

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