React Native集成CCAvenue支付网关遇10001错误,求AJAX解决方案
The core issue with your current implementation is that you're directly loading a self-submitting form in the WebView, instead of properly simulating the Node.js flow where you send a POST request to CCAvenue's initiateTransaction endpoint and receive the official payment page HTML in response. Here's how to fix this:
Step 1: Update React Native's Payment.js
We'll pass the encrypted parameters to your local HTML file via postMessage, letting the WebView handle the AJAX request to CCAvenue.
import React, { useState, useEffect, useRef } from 'react' import { WebView } from 'react-native-webview' var crypto = require('crypto') var qs = require('qs') const encrypt = (plainText, workingKey) => { var m = crypto.createHash('md5') m.update(workingKey) var key = m.digest() // Fix: Use single backslash for IV (double backslash was causing invalid encryption) var iv = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f' var cipher = crypto.createCipheriv('aes-128-cbc', key, iv) var encoded = cipher.update(plainText, 'utf8', 'hex') encoded += cipher.final('hex') return encoded } const data = { merchant_id: 'MERCHANT ID', order_id: '1232321', amount: '1.00', currency: 'INR', language: 'EN', redirect_url: 'redirect address', cancel_url: 'cancel address' } function Payment(props) { const webviewRef = useRef(null) useEffect(() => { setTimeout(() => { const body = qs.stringify(data) const workingKey = 'WORKING_KEY' const accessCode = 'ACCESS_CODE' const encRequest = encrypt(body, workingKey) // Send encrypted params to WebView's HTML webviewRef.current.postMessage(JSON.stringify({ encRequest, accessCode })) }, 200) }, [webviewRef]) const _onWebViewMessage = (message) => { const parsedMessage = JSON.parse(message.nativeEvent.data) if (parsedMessage.type === 'error') { console.error('Payment Error:', parsedMessage.error) } // Optional: Handle payment completion/redirect here later } return ( <WebView ref={webviewRef} originWhitelist={['*']} source={{ uri: 'file:///android_asset/widget/ccavenue.html' }} domStorageEnabled javaScriptEnabled allowUniversalAccessFromFileURLs onMessage={_onWebViewMessage} onError={e => console.log('Webview Error', e)} mixedContentMode='always' /> ) } export default Payment
Step 2: Implement AJAX in ccavenue.html
Add this code to your local HTML file to handle the POST request to CCAvenue and render the official payment page:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>CCAvenue Payment</title> </head> <body> <div id="loader">Loading payment gateway...</div> <script> // Listen for params from React Native window.addEventListener('message', function(event) { const { encRequest, accessCode } = JSON.parse(event.data) if (encRequest && accessCode) { sendPaymentRequest(encRequest, accessCode) } }) function sendPaymentRequest(encRequest, accessCode) { const xhr = new XMLHttpRequest() const ccaUrl = 'https://test.ccavenue.com/transaction/transaction.do?command=initiateTransaction' xhr.open('POST', ccaUrl, true) xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { // Replace current page with CCAvenue's official payment HTML document.body.innerHTML = xhr.responseText } else { const error = `Request failed with status ${xhr.status}` window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'error', error: error })) } } xhr.onerror = function() { window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'error', error: 'Network error connecting to payment gateway' })) } // Encode params to avoid invalid request issues const formData = `encRequest=${encodeURIComponent(encRequest)}&access_code=${encodeURIComponent(accessCode)}` xhr.send(formData) } </script> </body> </html>
Step 3: Fix Node.js Handler (For Reference)
Your existing Node.js code uses a GET request (which is incorrect). Here's the corrected version to match the proper CCAvenue flow:
var request = require("request"); var crypto = require('crypto'); var qs = require("querystring"); exports.postReq = function(requestBody, response) { var body = qs.stringify(requestBody), workingKey = 'WORKING_KEY', accessCode = 'ACCESS_CODE', encRequest = encrypt(body, workingKey); // Send POST request to CCAvenue request.post({ url: 'https://test.ccavenue.com/transaction/transaction.do?command=initiateTransaction', form: { encRequest: encRequest, access_code: accessCode }, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }, function(error, res, body) { if (error) { response.writeHeader(500, { "Content-Type": "text/plain" }); response.write('Error: ' + error); response.end(); return; } // Return CCAvenue's payment page HTML to client response.writeHeader(200, { "Content-Type": "text/html" }); response.write(body); response.end(); }); }; // Ensure encryption matches React Native implementation function encrypt(plainText, workingKey) { var m = crypto.createHash('md5'); m.update(workingKey); var key = m.digest(); var iv = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f'; var cipher = crypto.createCipheriv('aes-128-cbc', key, iv); var encoded = cipher.update(plainText, 'utf8', 'hex'); encoded += cipher.final('hex'); return encoded; }
Why Your Original Code Failed
Your initial React Native implementation loaded a self-submitting form directly from the file:// protocol. CCAvenue's servers often reject requests from local file contexts, and incorrect IV escaping in your encryption logic produced an invalid encRequest parameter. By using AJAX inside the WebView to simulate the server-side request flow, you match the valid context that your Node.js code uses.
内容的提问来源于stack exchange,提问作者Rajesh

