Hello!
2015-08-18 22:17 GMT+08:00 Zoom.Quiet:
> # 背景
> 历史遗留客户端, 只接受特定大小写的 HTTP 响应 HEAD 字段
>
> - 比如 FooBar: 1234567
> - 但是, 后来使用标准化库后,自动将字段名修订为 Foobar 类似字串
> - 客户端就无法接受了
一般地,可以用 ngx.header API 来做。为安全起见,先清空响应头,再生成响应头。例如:
local name = "FooBar"
ngx.header[name] = nil -- ensure that the existing header names
are erased completely
ngx.header[name] = "1234567"
但须注意,在此之前不能有任何 ngx.say/ngx.print/ngx.send_headers/ngx.eof
这些操作。因为这些操作都会触发发送响应头。响应头发送出去了,就不能再修改响应头了。
> - 同时,此时的 Nginx 是作为代理,将后端动态系统发布出来的,类似:
> + proxy_pass http://myapi/;
>
如果你使用 proxy_pass 的话,则你的 Lua 代码应该放在 header_filter_by_lua 中。
> ngx.header["X-My-Header"] = 'blah blah'
> local h = ngx.resp.get_headers()
> for k, v in pairs(h) do
> ngx.say(k,'\t', v)
> if k ~='x-my-header' then
> ngx.header["My-Header-X"] = 'blah blah'
> end
> end
>
你这里在修改响应头前调用了 ngx.say(),从而导致响应头被自动发送。所以会抛出下面那个错误。
>
> 报错:
> 2015/08/18 22:06:08 [error] 47371#0: *12 attempt to set
> ngx.header.HEADER after sending out response headers, client:
> 127.0.0.1, server: , request: "GET /echo HTTP/1.1", host:
> "127.0.0.1:8081"
>
> 如果将测试脚本部署在代理路径上,类似:
>
> location / {
> proxy_pass http://myapi/;
> content_by_lua_file conf/lua/echo.lua;
> }
>
这是初学者常犯的错误了,一个 location 不能有两个 content handler. 你这里 proxy_pass 是一个
content handler 而 content_by_lua 又是一个 content handler.
此二者会冲突,从而只有其中一个生效。正确的做法如我上面所说,使用 proxy_pass 时应结合使用
header_filter_by_lua.
Regards,
-agentzh