nodejs + express 如何拒绝大文件上传
发布于 6 年前 作者 anubiskong 9554 次浏览 最后一次编辑是 3 年前

我想在post header到达之后, 文件开始上传之前或者刚开始上传时拒绝post请求 目前使用的方式是在加载bodyparse时设置 app.use(express.bodyParser({ limit: 1000000 //1m })); 这样一来浏览器确实收到一个413,而且后台也没有临时文件出现, 但是浏览器依然在上传文件, 我不知道后台有没有在继续处理这个请求, 如果有的话应该也是占用了不少资源和带宽, 如何能彻底的把文件大上传拒绝掉呢?

15 回复

传统的express上传文件是,post header发生完毕,然后添加到服务器的临时目录后,在根据size()方法判断是否过大,如果过大就返回413。 而在express.bodyParser( { limit: 3242 } ) 设置最大限制也的确发送了header 头之后,当文件过大也不会拷贝到临时目录 你说的这种,应该后台在处理,否则怎么运用limit属性判断文件是否过大呢

header 中的 Content-Length

在文件上传了1m以后发现依然没有传完就立即断开请求, 这也是一种策略. 无论使用什么策略, 我现在只是不知道完全取消中断请求的方法而已

function OnError(status) {
  var xhr = this;
  if (status === 413) {
    xhr.abort();
  }
}

额,用流的形式读取,把req当做流对象,请求体当做读取的流数据,我试下,不知道可以不

现在我发现我在正文中说的方法不稳定, 有的时候会立即发出413, 有的时候是文件传输的过程甚至结束后才发出

我说了我只是不知道彻底取消请求的方法, 其他都搞定了

上面的貌似可行

看起来好像是前端用的, 我想要后端用的

@anubiskong 既然都返回413了,那服务器就已经返回了,问题可能是浏览器的socket还在,可以用netstat查看是否那个socket连接还在,另:如果还不放心,用nginx代理,同样可以限制大小,那样如果超过最大设置,请求压根不会到node进程。

如果socket还在, 应该怎么处理呢? 我试着req.socket.end(); 但是没有效果

@anubiskong

首先,看看socket.end()的解释:

Half-closes the socket. i.e., it sends a FIN packet. It is possible the server will still send some data.

因此socket.end()不会关闭浏览器的连接,而你应该调用的是socket.destroy():

Ensures that no more I/O activity happens on this socket. Only necessary in case of errors (parse error or so).

另外确认你服务器进程两个地方:

  1. 那个socket连接还在的话,状态是否是ESTABLISHED,如果是WAIT_TIME或者其它的状态是没有问题的
  2. 检查相应fd是否存在

你自己描述问题也说了:

  1. 服务器返回了413,浏览器收到了413
  2. 服务器没有保存文件
  3. 浏览器依然在上传

针对第三点,你判断浏览器依然在上传的标准是什么呢?Pending么?在chrome调试器里都返回413了,按道理是不可能出现Pending状态的。所以你按照我第一次给的代码,直接abort()是最简单粗暴的办法。

另外,见代码:

  1. https://github.com/stream-utils/raw-body/blob/master/index.js#L27-L39
  2. https://github.com/expressjs/body-parser/blob/master/index.js#L43

express的中间件body-parser只是将socket暂停了(通过调用.pause()),然后抛出错误,所以你要也可以这么写:

app.use(function onError(err, req, res) {
  if (err && err.status === 413) 
    req.socket.destroy();
})

@yorkie 我测试中发现了很多奇怪的现象 其实浏览器没有立即收到413, 而是在文件上传之后收到的, 这是在上传4g的大文件时发现的, 一开始我用的是100m的文件, 瞬间传完, 所以没有发现. 另外是, 我试着写了一段代码监控data事件, 当data累计长度超过1m的时候取消所有的data事件和end事件监听(req.removeAllListeners), 然后上传一个100m的文件测试, 我发现这个代码在一次上传请求中被执行了7次, 没有搞明白是为什么 还有就是4g的大文件上传, 即便传完了也没有413发到浏览器, 浏览器什么回复也没有收到, 如果看jquery的xhr, 会发现status=404…

@anubiskong 你可以仔细看看raw-body这个lib的实现,express的limit是通过它实现的,它是在如果没有提供length的前提下会在data事件中计算出当前的received,超过limit后413,取消事件监听是因为raw-bodycleanup(). 最好是发出部分代码才比较好分析。

我的邮箱:yorkiefixer@gmail.com

@yorkie 已发送, 我在信里做了简单的说明

回到顶部