在Nginx(和lua)中提供大于最小文件大小的图像。

我正在尝试检查请求的文件是否超过某个大小(比如说250字节),如果是,则服务端将提供该文件;否则,将提供一个默认图像。

然而,我得到了意想不到的结果。检查正文长度的代码似乎没有被执行,于是no_image_small.png会被提供。不过,res.status == 200 看似有效:

  • 图像请求大小: 17 字节
  • no_image_small.png 大小:3030 字节

nginx 错误日志:

2014/12/01 11:52:57 [error] 6033#0: *1 subrequests cycle while processing "/images/blue_image_small.jpg", client: 127.0.0.1, server: images.dev, request: "GET /images/blue_image_small.jpg HTTP/1.1", subrequest: "/images/blue_image_small.jpg", host: "images.dev:8080"
2014/12/01 11:52:57 [error] 6033#0: *1 lua entry thread aborted: runtime error: rewrite_by_lua:2: failed to issue subrequest: -1
stack traceback:
coroutine 0:
    [C]: in function 'capture'
    rewrite_by_lua:2: in function <rewrite_by_lua:1>, client: 127.0.0.1, server: images.dev, request: "GET /images/blue_image_small.jpg HTTP/1.1", subrequest: "/images/blue_image_small.jpg", host: "images.dev:8080"

我的 nginx 配置:

```` server { listen 8080; server_name images.dev www.images.dev; root /home/syz/dev/images/;

location ~* ^/images/(.*_small.) {
    rewrite_by_lua '
        local res = ngx.location.capture(ngx.var.uri)
        if res.status == 200 then
            local blength = string.len(res.body)
            if blength > 250 then
                ngx.say(res.body)
                ngx.exit(ngx.OK)
            else
                ngx.redirect("/images/no_image.small.png")
            end
        else
            ngx.redirect("/images/no_image_small.png")
        end
    ';
}

}

``` `

点赞
用户1058509
用户1058509

而不是捕获和读取响应体长度,你可以在验证时读取 Content-Length 头部(这更快)。

我在生产环境中有一个类似的验证,如下:

location ~*/img/.*\.(png|jpg|jpeg) {
           set $max_image_size 15000;
           # default redirect if requested image too big
           error_page 412 = @default_image_loc;

           #serving the content
           root  /local_server/root/;

           #validating response
           header_filter_by_lua '
             local image_size = tonumber(ngx.header.content_length)
             if image_size > tonumber(ngx.var.max_image_size) then
               ngx.log(ngx.NOTICE, string.format("invalid image size <%s>" , image_size))
               ngx.exit(412)
             end
          ';
}

location @default_image_loc {
        try_files "/img/default_image.png" @none;
}

访问日志将保持干净,因为 412 跳转是内部的。

2014-12-02 23:06:28