njs踩坑: 文件上传

in 前后端开发 with 1 comment

njs是一个烂,烂,烂的东西,文件上传方面一坨屎
上传吧,客户端好好的,动不动0字节

错误

然后多方求证,甚至还翻找了issue,终于让我找到了 解决方法

句法: client_body_in_file_only on | clean | off;
默认: 客户端主体在文件中仅关闭;
语境: httpserver,​location
决定 nginx 是否应将整个客户端请求主体保存到文件中。此指令可以在调试期间使用,或者在使用变量 $request_body_file 或 模块 ngx_http_perl_module的 $r->request_body_file 方法时使用。
当设置为该值时on,请求处理后不会删除临时文件。
该值clean将导致请求处理后留下的临时文件被删除。

先设置 client_body_in_file_only: clean
然后加大缓冲区

client_max_body_size                    256m;
client_body_buffer_size                 128m;

注意量力而行,比如我的服务器(光猫)内存只有512m

~ $ cat /proc/meminfo
MemTotal: 470944 kB

接下来是判断body在文件中还是在Buffer内
Buffer:

try{
    // 内容不在内存中
    if(h.requestBuffer && h.requestBuffer.length == 0) throw 0;
    // 直接使用h.requestBuffer
    // ......
}catch(_e){
    // 尝试读取文件
    const file = h.variables.request_body_file;
    if(!file) return h.return(500, 'Body read failed');
    const body = await fs.promises.open(file, 'r');
    // 使用body
    // ......
}

文本:

let text = '';
try {
    // 在Buffer内:直接可以使用
    if (!h.requestText) throw 1;
    text = h.requestText;
} catch (_e) {
    // 在文件中:打开
    const file = h.variables.request_body_file;
    if (!file) return h.return(500, 'Body read failed');
    text = (await fs.promises.readFile(file)).toString('utf8');
}
// 使用text
// ......

上传成功

Responses
  1. [...]详情请参看我的这篇踩坑文章 https://hi.imzlh.top/2024/07/09.cgi 总之,这是Nginx的Buffer,而客户端的上传如果大于client_body_buffer_size会被写入文件并暴露在变量中 h.variables.request_body_file[...]

    Reply