在 Express 中发送二进制文件导致 ECONNABORTED

Sending Binary File in Express leads to ECONNABORTED

我目前正在为后端进行一些测试,但我一直感到困惑,特别是一项测试有时会通过,有时却不会。如果某些特定的 header 不存在,我的警卫会发生错误以拒绝请求。所以在我的测试中,应用程序看起来类似于此

beforeEach(() => {
    app = express();
    const router = express.Router();
    router.post('/media/upload',      
      addSpies,
      PostMediaGuard(sinon.stub().resolves(true)),
      multer(getMulterOptions()).fields([{ name: 'File', maxCount: 1 }]),
      upload
    ); 

    app.use('/', router);
  });

现在添加间谍只会将间谍添加到我的请求、资源和下一步,然后继续。错误发生在我的 PostMediaGuard 中。在这里,我将检查是否存在 header,如果不存在则拒绝

PostMediaGuard

if(typeof(req.headers['x-some-header']) !== 'string')
      return res.status(400).end('No valid RealmId in Header. Please set X-RealmId');

    if(!await _userMayUploadMediaFile(
      req.headers['x-some-header'],
      req.headers.authorization as string,
      req.user
    ))
      return res.status(403).end(`Not allowed to upload media`);

next();

现在,对于我的测试,我将使用 supertest 向我的应用程序发出请求。请求看起来像这样

测试

await request(app)      
        .post('/media/upload')      
        .attach('File', path.join(__dirname, '../../test/media/dummy.jpg'));   

现在,如果我调试一切正常,我将点击该行将状态设置为 400 并结束 PostMediaGuard 中的请求。有时在那之后测试被断言就好了,有时我会用下面的 Stack

得到 ECONNABORTED

stack:"Error: write ECONNABORTED
at afterWriteDispatched (internal/stream_base_commons.js:150:25)
at writeGeneric (internal/stream_base_commons.js:141:3)
at Socket._writeGeneric (net.js:770:11)
at Socket._write (net.js:782:8)
at doWrite (_stream_writable.js:431:12)
at writeOrBuffer (_stream_writable.js:415:5)
at Socket.Writable.write (_stream_writable.js:305:11)
at ClientRequest._writeRaw (_http_outgoing.js:295:17)
at ClientRequest._send (_http_outgoing.js:271:15)
at ClientRequest.end (_http_outgoing.js:732:10)
at Transform.onend (_stream_readable.js:691:10)
at Object.onceWrapper (events.js:299:28)
at Transform.emit (events.js:210:5)
at endReadableNT (_stream_readable.js:1183:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)"

现在我假设由于请求的 form-data 中正在发送文件,所以我假设后台正在进行一些流式处理,我正试图在请求完成之前结束该请求。但是我还没有开始任何处理数据的事情,比如创建一个读取流或试图将其存储在数据库中。 (因为守卫的要点是,如果所需的 header 不存在,我将不会这样做)。实际上,到目前为止,我找到的关于该主题的所有答案都是由于一些异步流方法开始并试图在完成之前结束请求。但是因为那时我还没有开始,所以我不知道我哪里错了

知道问题出在哪里吗?

现在这似乎是超级测试的问题(Issue on GitHub)

但是至少有一种解决方法可以通过将连接设置为在 header 中保持活动状态来使其工作。

如果你看一下我在问题中的请求示例,请将其更改为类似这样的内容

await request(app)      
        .post('/media/upload')      
        .attach('File', path.join(__dirname, '../../test/media/dummy.jpg'))
        .set('Connection', 'keep-alive'); 

现在我仍然无法理解超级测试到底发生了什么。 This issue 声明在 form-data 请求时可能会调用双重回调,因此它可能与此相关。

到目前为止我还不明白根本原因,但我会在找到后立即在这里更新。至少现在有一个解决方法可以让它工作。