帮我解决问题,发红包~ 偶尔提示错误 Cannot set headers after they are sent to the client ?
发布于 5 年前 作者 xulayen 6751 次浏览 来自 问答

You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

const rp=require('request-promise');


rp(...).then(...).catch(...).finally(function () {
        // This is called after the request finishes either successful or not successful.
        return res.send(_objResult);//这句偶尔会报错
});

上面那段是一个公共方法,我封装成了一个ApiCall,大部分都会走这个函数,有没可能是并发导致一个请求还未发送出去另一个请求又进来了?请大神帮忙看下~

QQ 617284237

image.png

29 回复

有多次调用res.send之类的方法就会出现这种

@zengming00 那意思是报错的这个地方之前还调用了一次send之类的方法么。但是并没有额

@xulayen 仔细查查,肯定有,或者不是在之前而是在之后

@zengming00

JSBINhttps://jsbin.com/xunututehi/edit?js

return res.redirect(_forword); //这句话 偶尔报错,但是之前之后也没有 res.send之类的操作

你的catch里面有没有返回呢? 如果有错误了,最后还会走finally

@shadow88sky image.png

图上是源码 705行。

这个,在生产环境下有时候也会出现 这个错


Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:470:11)
    at ServerResponse.header (/mnt/www/pgyer/nodejs-middle/node_modules/express/lib/response.js:771:10)
    at ServerResponse.append (/mnt/www/pgyer/nodejs-middle/node_modules/express/lib/response.js:732:15)
    at ServerResponse.res.cookie (/mnt/www/pgyer/nodejs-middle/node_modules/express/lib/response.js:857:8)
    at Request.cookie [as _callback] (/mnt/www/pgyer/nodejs-middle/server/api/admin/account/index.js:705:17)
    at Request.self.callback (/mnt/www/pgyer/nodejs-middle/node_modules/request/request.js:185:22)
    at Request.emit (events.js:198:13)
    at Request.<anonymous> (/mnt/www/pgyer/nodejs-middle/node_modules/request/request.js:1161:10)
    at Request.emit (events.js:198:13)
    at IncomingMessage.<anonymous> (/mnt/www/pgyer/nodejs-middle/node_modules/request/request.js:1083:12)
    at Object.onceWrapper (events.js:286:20)
    at IncomingMessage.emit (events.js:203:15)
    at endReadableNT (_stream_readable.js:1129:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)

请确保这些设置在 send之前 只要发送 send执行过一次,再涉及到 set cookie、set header这种设置 http head 部分的都会报错

send只能发送一次吧,write可以多次

@zhhb 是在send之前,现在又出现了一次

@zhhb

image.png 这句话之前没有任何 set cookie、set header 的操作了

@zhhb 这里用了一个异步promise ,报错好像是报这个promie有问题。


router.get('/:customerid/:accode/:timestamp/:sign', async function (req, res, next) {

                var reply = await client.get(`${key}`);
            ...
                    return res.redirect(reply);
     ...

});


下面是promise功能代码,看下是哪里没有捕获promise异常?



const config = require('../../config/index');
var redis = require("redis"),
    client = redis.createClient(config.redis);


client.on("error", function (err) {
    console.log("Error " + err);
});

client.on('ready', function (res) {
    console.log('redis is ready,Go!');
});

function clientCache() { }

let text = async (key) => {
    let doc = await new Promise((resolve) => {
        // setTimeout(() => {
        //     Promise.reject(new Error('unhandledrejection'))
        // }, 0);
        client.get(key, function (err, res) {
            return resolve(res);
        });
    }).catch((e) => {
        console.log(e)
    });
    return JSON.parse(doc);

};

clientCache.set = function (key, value) {
    value = JSON.stringify(value);
    return client.set(key, value, function (err) {
        if (err) {
            console.error(err);
        }
    });
};

clientCache.get = async (key) => {
    return await text(key);
};

clientCache.expire = function (key, time) {
    return client.expire(key, time);
};


module.exports = exports = clientCache;

@shadow88sky @zengming00 @zhhb @ounana 大神们,帮我看看什么问题么

你看一下请求的返回头是不是开启了keep-alive。因为node服务端keepalive的超时默认是5000毫秒,要不把服务端默认时间改大,要不把客户端keepalive时间改小。否则客户端超时大于服务端,服务端TCP关了,但是客户端还以为这个TCP还在,准备复用也会报这个错。

@zy445566 没有开启呢

@zy445566 报错信息:

/mnt/www/pgyer/nodejs-middle/server/api/frontEnd/forword/index.js:163:40 代码就是下面的 return res.redirect(_forword);

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at ServerResponse.setHeader (_http_outgoing.js:470:11) 
at ServerResponse.header (/mnt/www/pgyer/nodejs-middle/node_modules/express/lib/response.js:771:10) at ServerResponse.location (/mnt/www/pgyer/nodejs-middle/node_modules/express/lib/response.js:888:15) 
at ServerResponse.redirect (/mnt/www/pgyer/nodejs-middle/node_modules/express/lib/response.js:926:18) 
at Request.redirect [as _callback] (/mnt/www/pgyer/nodejs-middle/server/api/frontEnd/forword/index.js:163:40) 
at Request.self.callback (/mnt/www/pgyer/nodejs-middle/node_modules/request/request.js:185:22)
at Request.emit (events.js:198:13) at Request. (/mnt/www/pgyer/nodejs-middle/node_modules/request/request.js:1161:10) 
at Request.emit (events.js:198:13) at IncomingMessage. (/mnt/www/pgyer/nodejs-middle/node_modules/request/request.js:1083:12)
at Object.onceWrapper (events.js:286:20) at IncomingMessage.emit (events.js:203:15) at endReadableNT (_stream_readable.js:1129:12)
at process._tickCallback (internal/process/next_tick.js:63:19)

源码:

这是/redis/index.js


const config = require('../../config/index');

var redis = require("redis"),
    client = redis.createClient({
        ...config.redis
    });


client.on("error", function (err) {
    console.error("Errorssss " + JSON.stringify(err));
});

client.on('ready', function (res) {
    console.log('redis is ready,Go!');
});



function clientCache() { }




let text = async (key) => {
    let doc = await new Promise((resolve, reject) => {
        client.get(key, function (err, res) {
            if (err) {
                console.log(err);
                reject(err);
                return;
            }
            return resolve(res);
        });
    }).catch((e) => {
        debugger;
        console.error(e);
    });

    return doc ? JSON.parse(doc) : null;

};

clientCache.set = function (key, value) {
    value = JSON.stringify(value);
    return client.set(key, value, function (err) {
        if (err) {
            console.error(err);
            client = redis.createClient({
                ...config.redis
            });
            return clientCache.set(key, value);
        }
    });
};

clientCache.get = async (key) => {
    // client = redis.createClient({
    //     ...config.redis
    // });
    return await text(key);
};

clientCache.expire = function (key, time) {
    return client.expire(key, time);
};


module.exports = exports = clientCache;

这是/forword/index.js


const Express = require('express');
const router = Express.Router();
// const codeState = require('../../../config/codeState');
// const result = require('../../../config/index').result;
// const token = require('../../../common/token');

const {
    config,
    SelfCookie,
    codeState,
    result,
    log,
    token,
    HttpApi,
    Client,
    DEBUGGER,
    ResultFactory
} = require('../../../namespaceMain');

const request = require('request');

const md5 = require('md5');

const client = require("../../../common/redis");

/**
 * @api {get} /forword/[customerid]/[accode]/[timestamp]/[sign] 前端分流管理✔
 * @apiDescription 前端主入口
 * @apiVersion 1.0.0
 * @apiSuccessExample {json}
 *      Success-Response:
 *      跳转至前端活动页面……
 * 
 * @apiErrorExample {json} 
 *      Error-Response:
 *      跳转至前端Error页面……
 * 
 * @apiGroup FrontEnd
 * @apiParam {string} customerid  客户编号
 * @apiParam {string} accode 数码
 * @apiParam {string} timestamp 时间戳
 * @apiParam {string} sign 签名,加密方式`md5(customerid+accode+token+timestamp)`;token为约定的值
 */
router.get('/:customerid/:accode/:timestamp/:sign', async function (req, res, next) {

    try {
        debugger;

        const _result = '网络出了个小差……';

        console.log(`/:customerid/:accode/:timestamp/:sign ${JSON.stringify(req.params)}`);

        var _customerid = req.params.customerid,

            _accode = req.params.accode,

            __header_sign = req.params.sign,

            __timestamp = req.params.timestamp,

            __sign = md5(_customerid + _accode + config.ZhshToNodejsToken[_customerid] + __timestamp),

            _param_notnull = (_customerid && _accode && __header_sign),

            _b_tokenisok = (__sign === __header_sign),

            _code_sign = `${_customerid}_${_accode}_${__timestamp}_${__sign}`;


        log.logger.info(`/:customerid/:accode/:timestamp/:sign /${_customerid}/${_code_sign}/${__timestamp}/${__sign} SessionId: ${req.session.id}  GetParameter: \n `);

        console.log(`/forword/index - /${_customerid}/${_code_sign}/${__timestamp}/${__sign} SessionId: ${req.session.id}`);

        if (!config.EnableZhshToNodejsToken) {

            _param_notnull = (_customerid && _accode);

            _b_tokenisok = true;
        }

        const key = `forword:${_customerid}:${_accode}`;

        const key_info = `forword:${_customerid}:actinfo:${_code_sign}`;

        if (!_param_notnull) {
            log.logger.info('/forword/index 参数为空或值错误' + "\n");
            console.log('/forword/index 参数为空或值错误' + "\n");
            return res.send(_result);
        }

        if (!_b_tokenisok) {
            log.logger.info('/forword/index  签名校验不成功' + "\n");
            console.log('/forword/index  签名校验不成功' + "\n");
            return res.send(_result);
        }

        console.time('/forword/index');

        var reply = await client.get(`${key}`);

        if (reply) {

            console.log(`/forword/index - 已缓存 ${JSON.stringify(reply)}`);

            console.timeEnd('/forword/index');

            return res.redirect(reply);

        } else {


            var _f = {
                customerid: _customerid,
                accode: _code_sign
            }

            log.logger.info('/forword/index SessionId:' + req.session.id + ' Begin:', JSON.stringify(_f) + "\n");

            request({
                url: HttpApi.Home.Index,
                method: "POST",
                json: true,
                headers: {
                    "content-type": "application/json",
                    "Authorization": req.session.Authorization
                },
                form: _f
            }, function (error, response, body) {

                //log.logger.info(JSON.parse(body)+ "\n");

                var str_body = JSON.stringify(body);

                log.logger.info('/forword/index SessionId:' + req.session.id + ' End:', str_body + "\n");

                console.timeEnd('/forword/index');

                console.log(`/forword/index - Response:${str_body}`);

                if (body.success) {

                    if (body.result && body.result.module && body.result.module.template && body.result.module.template.url && body.result.module.id) {

                        var _type = body.result.module.template.url;

                        var _moduleid = body.result.module.id;

                        var _forword = `${config.FrontendToDomain}${_type}${_customerid}/${_moduleid}/${_code_sign}`;
                        
                        client.set(`${key}`, _forword, 'EX', (60 * 1 * 30));//30 分钟失效

                        client.set(`${key_info}`, str_body, 'EX', (60 * 1 * 30));//30 分钟失效

                         return res.redirect(_forword);//这句话报错

                    } else {

                        log.logger.info('/forword/index  模块未配置成功!' + "\n");
                        console.log('/forword/index  模块未配置成功!' + "\n");
                        return res.send(_result);

                    }

                } else {

                    log.logger.info('/forword/index 返回 false' + "\n");
                    console.log('/forword/index 返回 false' + "\n");
                    return res.send(_result);

                }


            });


        }

    } catch (e) {

        console.error('00000000000000000000000000000000');
        console.error(JSON.stringify(e));

    }













});






module.exports = router;

你是不是后面还有啥中间建执行了?

@heguangda 后面没有中间件执行,前面有中间件

回到顶部