0x00 场景
一般我们在提供图片资源下载服务的时候 ,直接使用
nginx
的alias
指令就可以很好的实现这个功能.但是, 现在有这样的需求:
通过访问一个带参数的
URL
, 要求服务器能够动态返回相应的图片资源(比如有些参数值不存在的时候,使用默认值).
换句话说, 这样的URL
, 可以直接写在html
的src
标签内使用, 能够正常显示图片.
0x01 思路
对于这样的需求, 我们当然可以用万能的
Spring Boot
去开发一个后端服务去搞.
但是, 作为一个酷爱折腾,而且对性能有极度要求的后端开发, 我们断然选择了kong
插件的形式去解决这个问题.
静态图片服务
首先想到的就是服务端的重定向指令,
那么首先我们先要有一套对外服务的静态图片请求服务,这个比较容易实现.-
插件逻辑
- 解析请求路由和参数
- 过滤或重写参数, 组合得到要重定向的路由
- 重定向请求(向客户端返回图片)
0x02 静态资源访问服务
这里的配置方法, 完全参考nginx
配置思路即可.
- 添加
kong_nginx
的静态访问路由
kong
中更新kong_nginx.conf
方法不熟悉的同学,请翻看以前的文章,这里不(jiu
)再(shi
)赘(tai
)述(lan
).
cd /usr/local/share/lua/5.1/kong/templates
vim nginx_kong.lua
找到 location = /kong_error_handler
这一行, 在它的上面添加下面的配置:
location /static/ {
alias /opt/share/static/;
}
修改完成后, 记得 kong restart
- 复制图片文件夹
把图片文件夹复制到/opt/share/static
目录后, 完成配置.
请求图片URL: http://aaa.com/static/T00001/en/desc.png
0x03 插件编写
我们期待结果是, 请求http://aaa.com/get_image?key=T00001&lang=en&desc.png这样的
URL
也能返回上面的图片.
- 背景调查
因为我们要用到rewrite()
,所以先去查看一下官方文档,
可以了解到, 我们需要开发一个全局插件.
那么, 我们必需在这个插件里, 过滤一下请求路由(因为每一个请求都会在这个插件里执行)
- 代码实现
我们新建一个插件,命名为image-request
, 插件代码如下:
-- handler.lua
-- handler.lua
local BasePlugin = require "kong.plugins.base_plugin"
local CCHandler = BasePlugin:extend()
CCHandler.VERSION = "1.0.0"
CCHandler.PRIORITY = 10
function CCHandler:rewrite(config)
if kong.request.get_path() == '/get_image' then
-- 取URL参数
local key = kong.request.get_query_arg('key') or '-'
local lang = kong.request.get_query_arg('lang') or 'en'
local filename = kong.request.get_query_arg('filename') or 'desc.png'
-- 读取插件配置参数
local dic = {}
for _, v in ipairs(config.guide_settings) do
local _key, _lang = string.match(v, "^([^:]+):(.*)$")
dic[_key] = _lang
end
-- 如果key不存在的话, 返回404
local _lang = dic[key]
if _lang == nil then
return kong.response.exit(404, "404 not found",
{
["Content-Type"] = "text/plain",
})
end
-- 读取多语言信息,如果配置项里不存在的话,使用默认值 : en
if string.find(_lang, lang) == nil then
lang = 'en'
end
-- 拼接字符串
local _img_url = '/static/' .. key .. '/' .. lang .. '/' .. filename
ngx.req.set_uri(_img_url, true)
end
end
return CCHandler
看注释理解起来, 问题不大.
如果有需要的话, 可以把/get_image
也写到插件配置里, 那样更灵活.
-- schema.lua
local typedefs = require "kong.db.schema.typedefs"
-- 定义输入类型为 字符串 数组, 意为可以输入多个字符串
local colon_string_array = {
type = "array",
default = {},
elements = { type = "string", match = "^[^:]+:.*$" },
}
return {
name = "image-request",
fields = {
{ protocols = typedefs.protocols_http },
{ config = {
type = "record",
fields = {
-- 插件配置页
{ guide_settings = colon_string_array }
},
},
},
},
}
插件参数guide_settings
用于配置已经支持的key
和语言信息.
0x04 启用插件
- 修改
/etc/kong/kong.conf
vim /etc/kong/kong.conf
### 找到 plugins 这一行,添加插件名称 image-request
plugins = bundled, image-request
### 重启kong
kong restart
- 配置插件
添加全局插件 , 并配置参数T00001:en
,记得要按回车
0x05 验证
这里是测试链接, 主要以key
关键信息, 后面两个字段都有默认值.
- 应该请求成功的链接
0x06 小结
本文实现内容并不复杂, 笔者最开始天真的以为在
access()
下执行ngx.req.set_uri()
操作应该就可以了, 然并卵.最后还是查看了相关文档后, 才找到正确的方向.
看来, 各个生命周期做什么事情, 还是应该事先多了解一下比较好