NodeJS 在ExpressJS [ERR_HTTP_HEADERS_SENT] [duplicate]中发送到客户端后无法设置头

carvr3hs  于 2023-06-05  发布在  Node.js
关注(0)|答案(2)|浏览(255)

此问题已在此处有答案

Error: Can't set headers after they are sent to the client(47回答)
2小时前关闭
我有一个photoController.js文件,它有一个“create”函数,当一个post请求到url时会被调用:/photoCreate被触发。该函数然后运行带有人脸检测的python脚本,以进行2FA身份验证。如果脚本返回TRUE,我想发送一个200 OK请求,如果返回false,我将稍后在我的android studio应用程序中接收这些响应,以便让用户通过或拒绝它们。我遇到一个“[ERR_HTTP_HEADERS_SENT]:无法设置发送到客户端后的标头”错误。这个错误出现在return res.status(500).json({行上,我已经为此绞尽脑汁5个小时了,我觉得我错过了一些微不足道的东西。帮助是很高兴地赞赏。

create: function (req, res) {
    var photo = new PhotoModel({
        path: "/images/" + req.file.filename,
        postedBy: req.session.userId,
    });

    fs.access(`public/images/${req.session.userId}/${req.session.userId}.sav`, fs.constants.F_OK, (err) => {
        if (err) {
            const createModelScript = spawn('python', ['python/faceCreateModel.py', `public/images/${req.session.userId}`, "python/faces_false", `public/images/${req.session.userId}/${req.session.userId}`]);
            createModelScript.stdout.on('data', (data) => {
                // Process and handle the output from the Python script
                const result = data.toString();
                console.log(result);
            });
            createModelScript.stderr.on('data', (data) => {
                const error = data.toString();
                console.log(error);
            });
        } else {
            const files = fs.readdirSync(path.join('public/images', req.session.userId));
            const sortedFiles = files.map((filename) => {
                const filePath = path.join('public/images', req.session.userId, filename);
                const stat = fs.statSync(filePath);
                return {
                    filename,
                    createdAt: stat.birthtimeMs,
                };
            }).sort((a, b) => b.createdAt - a.createdAt);
            const recentImage = sortedFiles[0].filename;
            const faceTestScript = spawn('python', ['python/faceTestImage.py', `public/images/${req.session.userId}/${req.session.userId}.sav`, `public/images/${req.session.userId}/${recentImage}`]);
            faceTestScript.stdout.on('data', (data) => {
                const result = data.toString();
                console.log(result);
                if (result.trim() === 'true') {
                    return res.status(200).json({
                        message: 'Face test passed successfully'
                    });
                } else {
                    return res.status(400).json({
                        message: 'Face test failed'
                    });
                }
            });
            faceTestScript.stderr.on('data', (data) => {
                const error = data.toString();
                console.log(error);
ERROR HERE --->> ** return res.status(500).json({**
                    message: 'Error during face test',
                    error: error
                });
            });
        }
    })

    photo.save(function (err, photo) {
        if (err) {
            return res.status(500).json({
                message: 'Error when creating photo',
                error: err
            });
        }

        return res.status(201).json(photo);
        //return res.redirect('/photos');
    });
},

我试过删除每一个res.status语句,但如果脚本返回true或false,则会发送这些语句,但这不起作用。我还试过将res.status移动到photo.save函数中,并使用if语句,但这不起作用。请注意,如果我删除2个result.status(200)和(500)语句,这将非常好地工作,但当我添加这些语句时,我会得到这个错误。

oewdyzsn

oewdyzsn1#

看起来像是在已经发送了响应之后,您试图向客户端发送响应。
在您的代码中,您试图在createModelScript.stdout.onfaceTestScript.stdout.on的回调函数中发送多个响应。
您应该确保只发送一次响应。下面是一个示例:

create: function (req, res) {
    var photo = new PhotoModel({
        path: "/images/" + req.file.filename,
        postedBy: req.session.userId,
    });

    fs.access(`public/images/${req.session.userId}/${req.session.userId}.sav`, fs.constants.F_OK, (err) => {
        if (err) {
            const createModelScript = spawn('python', ['python/faceCreateModel.py', `public/images/${req.session.userId}`, "python/faces_false", `public/images/${req.session.userId}/${req.session.userId}`]);
            createModelScript.stdout.on('data', (data) => {
                // Process and handle the output from the Python script
                const result = data.toString();
                console.log(result);
            });
            createModelScript.stderr.on('data', (data) => {
                const error = data.toString();
                console.log(error);
            });
        } else {
            const files = fs.readdirSync(path.join('public/images', req.session.userId));
            const sortedFiles = files.map((filename) => {
                const filePath = path.join('public/images', req.session.userId, filename);
                const stat = fs.statSync(filePath);
                return {
                    filename,
                    createdAt: stat.birthtimeMs,
                };
            }).sort((a, b) => b.createdAt - a.createdAt);
            const recentImage = sortedFiles[0].filename;
            const faceTestScript = spawn('python', ['python/faceTestImage.py', `public/images/${req.session.userId}/${req.session.userId}.sav`, `public/images/${req.session.userId}/${recentImage}`]);
            faceTestScript.stdout.on('data', (data) => {
                const result = data.toString();
                console.log(result);
                if (result.trim() === 'true') {
                    // If face test passed, save photo and send the response
                    photo.save(function (err, savedPhoto) {
                        if (err) {
                            return res.status(500).json({
                                message: 'Error when creating photo',
                                error: err
                            });
                        }
                        return res.status(200).json({
                            message: 'Face test passed successfully',
                            photo: savedPhoto
                        });
                    });
                } else {
                    // If face test failed, send the response directly
                    return res.status(400).json({
                        message: 'Face test failed'
                    });
                }
            });
            faceTestScript.stderr.on('data', (data) => {
                const error = data.toString();
                console.log(error);
                return res.status(500).json({
                    message: 'Error during face test',
                    error: error
                });
            });
        }
    });
},

现在每个场景只发送一次响应。如果面部测试通过,则保存照片,并在photo.save()的回调中发送响应。如果face测试失败,则直接在if (result.trim() === 'true')块内发送响应。类似地,如果在face测试期间出现错误,则在faceTestScript.stderr.on回调中发送响应。

g2ieeal7

g2ieeal72#

我通过创建一个相应更新的标志testPassed并在最后发送一个响应来解决这个问题。问题是函数stdout.on()导致.send被多次发送,因为它本质上就像一个while循环,直到脚本完成。我为这样一个错误而自责,浪费了几个小时。我现在在on('close')函数中发送响应,该函数只在脚本完成时调用一次。

create: function (req, res) {
        var photo = new PhotoModel({
            path: "/images/" + req.file.filename,
            postedBy: req.session.userId,
        });
        
        var testPassed = false;

        fs.access(`public/images/${req.session.userId}/${req.session.userId}.sav`, fs.constants.F_OK, (err) => {
            if (err) {
                const createModelScript = spawn('python', ['python/faceCreateModel.py', `public/images/${req.session.userId}`, "python/faces_false", `public/images/${req.session.userId}/${req.session.userId}`]);
                createModelScript.stdout.on('data', (data) => {
                    // Process and handle the output from the Python script
                    const result = data.toString();
                    console.log(result);
                });
                createModelScript.stderr.on('data', (data) => {
                    const error = data.toString();
                    console.log(error);
                });
            } else {
                const files = fs.readdirSync(path.join('public/images', req.session.userId));
                const sortedFiles = files.map((filename) => {
                    const filePath = path.join('public/images', req.session.userId, filename);
                    const stat = fs.statSync(filePath);
                    return {
                        filename,
                        createdAt: stat.birthtimeMs,
                    };
                }).sort((a, b) => b.createdAt - a.createdAt);
                const recentImage = sortedFiles[0].filename;
                const faceTestScript = spawn('python', ['python/faceTestImage.py', `public/images/${req.session.userId}/${req.session.userId}.sav`, `public/images/${req.session.userId}/${recentImage}`]);
                faceTestScript.stdout.on('data', (data) => {
                    const result = data.toString();
                    if (result.trim() === 'TRUE') {
                        testPassed = true;
                    } else {
                        testPassed = false;
                    }
                });
                faceTestScript.stderr.on('data', (data) => {
                    const error = data.toString();
                    console.log(error);
                });
                faceTestScript.on('close', () => {
                if (testPassed) {
                    console.log("true");
                    return res.status(201).json({
                        photo,
                        testPassed: true
                    });
                } else {
                    console.log("false");
                    return res.status(500).json({
                        message: 'Test failed',
                        error: err,
                        testPassed: false
                    });
                }
            });
            }
        })

相关问题