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标准的方式返回给客户端,不用让模块直接操作响应对象。
具体步骤和代码修改如下:
- 参考ccavenue模块的
makePayment逻辑,自己实现一个生成支付表单的函数(因为模块内部的逻辑不复杂,我们可以直接复用); - 在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
相关产品推荐
相关产品推荐

