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