我必须先从
client --> server1
上传文件,然后从 server1 --> server2
上传。
注意:我知道我不应该将文件存储在heroku中,但实际上我不需要 要存储文件,我只需要它临时来制作一些 修改,然后将其传递给第二个服务,就可以了 其他修改。例如,让我们考虑 2 个微服务,其中一个 调整大小,一压缩。只是作为例子。无论如何,在这一步,我只是通过 文件不做任何修改。 无论如何,我也尝试过
但这是同样的问题。multer-s3
我在 Heroku 上部署的两台节点服务器上都使用
multer
。
我在 server1 上成功接收文件。当我将文件发送到 server2 时,heroku 上升:
server2
:at=warning code=H28 desc="Client Connection Idle" method=POST
BadRequestError: request aborted app[web.1]: at IncomingMessage.onAborted
server1
:code=H12 desc="Request timeout"
在
server1
,我以这种方式接收文件
/* ==============================
UPLOAD MIDDLEWARE
============================== */
const multer = require('multer');
let multer_storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, `${__dirname}/my_uploads`); // <-- be sure this dir already exists, otherwise create it
}
});
const form_upload = multer({ storage : multer_storage,
cb(null, true); } });
/* ==============================
API ROUTE
============================== */
app.post('/server1/files',
function(req, res)
{
form_upload.fields([{ name: 'file1' }, { name: 'file2' }])(req, res, (err, body) => {
// req.files contains file1 and file2 uploaded
var file1 = req.files["file1"][0];
var file2 = req.files["file2"][0];
...
}
然后,一直在
server1
,我以这种方式将这些文件发送到server2
const FormData = require('form-data');
const fs = require('fs');
const form = new FormData();
form.append("file1", fs.createReadStream(file1.path), file1.originalname);
form.append("file2", fs.createReadStream(file2.path, file2.originalname);
var headers = form.getHeaders();
var config = { headers:headers };
axios.post(URL_SERVER2_UPLOAD_API, form, config)
.then(function(response) { ... });
在
server2
上,我使用相同的 multer 中间件获取与 server1
中一样的文件。
在本地主机中一切正常,我可以在两台服务器之间传输文件。在 Heroku 上,我遇到了这些错误。这两个文件非常小(每个 150kb)。
====更新1
直接尝试
client --> server2
也失败了。这次我没有收到“超时”错误,但服务器只是在 req.files
中找不到文件,它是空的。
我不明白,因为它是完全相同的服务器配置,只是在另一个 heroku dyno 上。
与 multer-s3
相同:它在 localhost 上运行,而不是在 heroku 上运行。
这是服务器快速配置:
/** ======= server.js ======= */
var express = require('express');
var app = express();
app.use(express.urlencoded({ extended: true })); // support encoded bodies
var server = app.listen(port, function() {...});
app.use('/my_route', require("my_route.js"));
/** ======= my_route.js ======= */
var routes = express.Router();
function setupCORS(req, res, next) {
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Authorization,Content-type,Accept');
if (req.method === 'OPTIONS') {
res.status(200).end();
} else {
next();
}
}
routes.all('/*', setupCORS);
/* ==============================
UPLOAD MIDDLEWARE.
============================== */
const multer = require('multer');
let multer_storage = multer.diskStorage({..});
const form_upload = multer({..});
// API /my_route/upload
routes.post('/upload', form_upload.any(), function(req, res)
{
// req.files it's empty here!
});
我将首先回答一个不同的问题,这个问题已经有很多答案了,但我认为您的用例足够不同,足以保证一个问题。
在本地文件系统上存储上传内容是 Heroku1 上的反模式:它在大多数用例中无法按预期工作。 Dynos 有一个短暂的文件系统,这意味着对它们所做的任何更改都会在每次重新启动时丢失,这种情况经常发生且不可预测(每天至少一次)。
除非您只是在寻找临时存储空间,否则您将需要其他解决方案。 Heroku 建议 使用 Amazon S3 或 Azure Blob 存储之类的东西来存储上传内容。
我们通常谈论的两个好处是,上传可以在 dyno 重新启动后继续存在,并且水平缩放变得更加容易——您可以启动更多的 dyno,它们会自动看到上传的文件。您还可以处置测功机,而不必担心丢失数据。
但在您的用例中,还有另一个好处:您的两个服务都可以访问同一个存储容器,这根本不需要复制文件。这是一个更干净的解决方案,如果您想将上传内容存储任意时间,则需要在 Heroku 上进行。
1我认为这在其他地方也是一种反模式,因为与 Heroku 相同原因。
最后,我解决了在
multer-s3
上使用server1
,即能够接收req.files。然后我仅将链接传递给 server-2
,这将从 S3 下载文件。
即使这可能是一个更好的解决方案(正如 @Chris 所说),我也被迫使用 server1
作为第一个使用的服务,因为它是唯一正确接收文件的服务。我还是不知道为什么service2
收到的总是空的req.files