You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hapi框架中res.writeHead与res.write的等效替代方案咨询

解决Hapi中集成ccavenue支付网关的res.writeHead报错问题

你碰到的这个问题很典型——ccavenue的npm模块是基于Node.js原生http.ServerResponse对象设计的,它调用的res.writeHead、res.write这些方法,Hapi的reply对象根本没有,所以才会抛出TypeError: res.writeHead is not a function的错误。

下面给你两种解决方案,优先推荐第一种,更符合Hapi的设计规范:

方法一:适配Hapi的reply接口(推荐)

ccavenue的makePayment函数本质就是生成一段自动提交的HTML表单,我们完全可以自己拿到这段HTML,然后用Hapi标准的方式返回给客户端,不用让模块直接操作响应对象。

具体步骤和代码修改如下:

  1. 参考ccavenue模块的makePayment逻辑,自己实现一个生成支付表单的函数(因为模块内部的逻辑不复杂,我们可以直接复用);
  2. 在Hapi的路由handler中生成表单HTML,然后用reply(html).type('text/html')返回。

修改后的Hapi代码:

var ccavenue = require('ccavenue');
ccavenue.setMerchant("******");
ccavenue.setWorkingKey("*******************");
ccavenue.setRedirectUrl("/redirect-url");

// 复刻ccavenue的表单生成逻辑,返回HTML字符串
function generatePaymentForm() {
    const config = ccavenue.config;
    const helper = ccavenue.helper;
    const otherParams = ccavenue.otherParams;

    const errors = helper.checkRequiredField(config);
    if (errors.length > 0) {
        throw new Error(errors.join(', '));
    }

    const checksum = helper.getCheckSum(
        config.merchantId,
        config.orderAmount,
        config.orderId,
        config.redirectUrl,
        config.workingKey
    );

    let formHtml = `
        <form method='post' name='checkout' id='checkout' action='https://www.ccavenue.com/shopzone/cc_details.jsp'>
            <input type="hidden" name="Merchant_Id" value="${config.merchantId}">
            <input type="hidden" name="Amount" value="${config.orderAmount}">
            <input type="hidden" name="Order_Id" value="${config.orderId}">
            <input type="hidden" name="Redirect_Url" value="${config.redirectUrl}">
            <input type="hidden" name="Checksum" value="${checksum}">
            <input type="hidden" name="TxnType" value="A">
            <input type="hidden" name="ActionID" value="TXN">
    `;

    for (const key in otherParams) {
        formHtml += `<input type="hidden" name="${key}" value="${otherParams[key]}">`;
    }

    formHtml += `
        </form>
        <script type="text/javascript">
            document.getElementById('checkout').submit();
        </script>
    `;

    return formHtml;
}

module.exports = function(plugin, options, next) {
    plugin.route({
        method: 'GET',
        path: '/checkout',
        handler: function(request, reply) {
            try {
                const param = { 
                    billing_cust_address: 'Bangalore', 
                    billing_cust_name: 'Nitish Kumar' 
                };
                ccavenue.setOrderId("8981455644");
                ccavenue.setOrderAmount("1000");
                ccavenue.setOtherParams(param);

                const paymentForm = generatePaymentForm();
                // Hapi标准返回HTML的方式
                reply(paymentForm).type('text/html');
            } catch (err) {
                // 处理生成表单时的错误
                reply(err.message).code(500);
            }
        }
    });
    next();
};

方法二:直接获取Hapi的原生响应对象(不推荐)

如果你不想修改太多代码,也可以从Hapi的reply对象里拿到底层的Node.js原生res对象,传给ccavenue的makePayment方法。不过这种方式会绕过Hapi的响应处理流程,可能导致一些潜在问题(比如插件钩子失效、响应验证不生效等),所以只作为临时方案。

示例代码:

handler: function(request, reply) {
    const param = { 
        billing_cust_address: 'Bangalore', 
        billing_cust_name: 'Nitish Kumar' 
    };
    ccavenue.setOrderId("8981455644");
    ccavenue.setOrderAmount("1000");
    ccavenue.setOtherParams(param);

    // 获取底层原生res对象,暂停Hapi的响应处理
    const response = reply.response().hold();
    const nativeRes = response.res;

    // 调用ccavenue的方法
    ccavenue.makePayment(nativeRes);

    // 告诉Hapi响应已经处理完成
    reply.send();
}

总结一下,优先用第一种方法,既符合Hapi的设计理念,也能避免潜在的兼容性问题。

内容的提问来源于stack exchange,提问作者Satnam Sandhu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:24:24