error-handler.js 5.63 KB
/**
 * 404 错误
 * @return {[type]}
 */
const headerModel = require('../models/header');
const logger = global.yoho.logger;
const cache = global.yoho.cache.master;
const helpers = global.yoho.helpers;
const sender = global.yoho.apmSender;
const config = global.yoho.config;
const hostname = require('os').hostname();
const routeEncode = require('./route-encode');
const _ = require('lodash');
const limiterIpTime = 3600;


const replaceKey = '__refer__';
const checkRefer = helpers.urlFormat('/3party/check', {refer: replaceKey});

const forceNoCache = (res) => {
    if (res) {
        res.set({
            'Cache-Control': 'no-cache',
            Pragma: 'no-cache',
            Expires: (new Date(1900, 0, 1, 0, 0, 0, 0)).toUTCString()
        });
    }
};

const _err510 = (req, res, code, err) => {
    res.status(code);

    if (req.xhr) {
        return res.json({
            code: 510,
            message: err.message || '服务器繁忙请稍后重试!'
        });
    }

    const renderErrPage = (result) => {
        result = result || {};

        res.render('error/510', {
            module: 'common',
            page: 'error',
            err: err,
            title: '服务器繁忙 | Yoho!Buy有货 | 潮流购物逛不停',
            headerData: result.headerData
        });
    };

    return req.ctx(headerModel).requestHeaderData(req.yoho.channel).then(renderErrPage).catch(() => {
        renderErrPage();
    });
};

const _err500 = (req, res, code, err) => {
    res.status(code);

    if (req.xhr) {
        return res.json({
            code: 500,
            message: err.message || '服务器错误!'
        });
    }

    const renderErrPage = (result) => {
        result = result || {};

        res.render('error/500', {
            module: 'common',
            page: 'error',
            err: err,
            title: '服务器错误 | Yoho!Buy有货 | 潮流购物逛不停',
            headerData: result.headerData
        });
    };

    return req.ctx(headerModel).requestHeaderData(req.yoho.channel).then(renderErrPage).catch(() => {
        renderErrPage();
    });
};

exports.notFound = () => {
    return (req, res, next) => {
        forceNoCache(res);

        if (req.xhr) {
            return res.status(404).json({
                code: 404,
                message: '抱歉,页面不存在!'
            });
        }

        req.ctx(headerModel).requestHeaderData(req.yoho.channel).then((result) => {
            return res.status(404).render('error/404', {
                module: 'common',
                page: 'error',
                title: '页面不存在 | Yoho!Buy有货 | 潮流购物逛不停',
                headerData: result.headerData
            });
        }).catch(next);

    };
};

/**
 * 服务器错误
 * @return {[type]}
 */
exports.serverError = () => {
    const statusCodeList = [403];

    return async(err, req, res, next) => {
        forceNoCache(res);

        const uid = req.user ? req.user.uid : 0;
        const udid = _.get(req, 'cookies.udid', 'yoho');
        let errorCode = 500;

        err = err || {};

        err.code = parseInt(err.code || err.statusCode, 10) || 500;

        if (statusCodeList.indexOf(err.code) >= 0) {
            errorCode = err.code;
        }

        if (req.isApmReport && !err.apiError) { // apierror在node lib中已经上报过了 不需要再次上报
            // 上报服务端错误
            sender.addMessage({
                measurement: 'error-report',
                tags: {
                    app: global.yoho.config.appName, // 应用名称
                    hostname,
                    type: 'server',
                    route: `[${req.method}]${req.route && req.route.path}`, // 请求路由
                    reqID: req.reqID,
                    uid,
                    udid,
                    code: err.code || 500,
                    path: `[${req.method}]${routeEncode.getRouter(req)}`,
                    url: encodeURIComponent(req.originalUrl),
                    ip: _.get(req, 'yoho.clientIp', '')
                },
                fields: {
                    message: err.message,
                    stack: err.stack,
                    useragent: req && req.get('user-agent')
                }
            });
        }

        logger.error(`error at path: ${req.url}`);
        logger.error(err);

        if (err.code === 401) {
            if (req.xhr) {
                err.data = {refer: helpers.urlFormat('/signin.html', {refer: req.get('Referer') || ''})};
                return res.json(err);
            } else {
                return res.redirect(helpers.urlFormat('/signin.html', {refer: req.fullUrl()}));
            }
        } else if (err.apiRisk) {
            let remoteIp = req.yoho.clientIp;

            if (_.get(req.app.locals, 'pc.open.apmrisk', false)) {
                cache.setAsync(`${config.app}:limit2:${remoteIp}`, 1, limiterIpTime);
            } else {
                cache.setAsync(`${config.app}:limiter:${remoteIp}`, 1, limiterIpTime);
            }

            req.session.apiRiskValidate = true;

            if (req.xhr) {
                return res.status(510).json({
                    code: err.code,
                    data: {refer: checkRefer.replace(replaceKey, req.get('Referer') || '')}
                });
            }

            return res.redirect(checkRefer.replace(replaceKey, req.protocol + '://' + req.get('host') + req.originalUrl));

        } else if (err.code === 9999991 || err.code === 9999992) {
            return _err510(req, res, 510, err);
        }

        if (!res.headersSent) {
            return _err500(req, res, errorCode, err);
        }

        return next(err);
    };
};