Development is introduced

Because some later needs need to use alipay website payment business, and recently I learned the development of NodeJS backend, so I found some materials from the Internet, and alipay open platform has no ready-made Demo cases, only NodeJS SDK, so, I spent some time trying to develop a sample Demo using NodeJS for later development projects. Test DEMO: github.com/xiluotop/No…

Development steps

  • The text process from the creation of an order to the successful payment:

    Front-end page -> send order information to the server -> server confirmation information, Send confirmation information to the client -> client confirmation information send order request to the server -> server verifies order request information -> Server sends order generation like Alipay -> Alipay returns order data to the server -> Server sends form information of Alipay to the client -> Client jumps to the Payment page of Alipay -> Client payment success -> Alipay allows the client to jump to the page specified by the server -> Alipay asynchronously notifies the server of the payment result of the order -> The server receives the asynchronous notification for corresponding business processing.

  • The general process for Alipay to invoke the payment interface:

The preparatory work

  • Install the SDK tool of Alipay:www.npmjs.com/package/ali… npm install alipay-sdk
  • Obtain relevant information of Alipay application
    • appid
    • The secret key
      • Application of the private key
      • Application of public key
      • Alipay public key (it can be obtained from the secret key query on alipay Open platform)
    • The gateway
    • The steps of access are available at https://jiangck.com/articles/2019/08/10/1565412139037.html
  • The following table of contents should be prepared:

The development work

  • Configure the SDK
    • Create alipay_config.js this js script is used to set information about the SDK
    const fs = require('fs');
    const path = require('path');
    
    // Configure basic information here
    const AlipayBaseConfig = {
        appId: ' './ / application ID
        privateKey: fs.readFileSync(path.join(__dirname, './sandbox-pem/private_pem2048.txt'), 'ascii'), // Apply the private key
        alipayPublicKey: ' '.// Alipay public key
        gateway: 'https://openapi.alipaydev.com/gateway.do'.// The application gateway of Alipay is the gateway of sandbox environment
        charset:'utf-8'.// Character set encoding
        version:'1.0'.// Version, default 1.0
        signType:'RSA2'		// The decoded version of the secret key
    };
    
    module.exports = {
        AlipayBaseConfig: AlipayBaseConfig,	// Expose the configuration module for initial call
    }
    Copy the code
  • Create createOrder.js file to encapsulate the module that generates alipay orders
    • Import SDK environment:const AlipaySDK = require("alipay-sdk").default;
    • Import configuration:const alipayConfig = require(path.join(__dirname, './alipay_config.js')); // The previously defined alipay_config.js configuration module
    • Get the alipaySDK instantiation object and initialize it:const alipay = new AlipaySDK(alipayConfig.AlipayBaseConfig)
    • Encapsulation createOrder
      • According to the official example: www.yuque.com/chenqiu/ali… , Alipay. Trade.page. Pay (unified ordering and payment page interface) returns an HTML fragment at last, so formData is needed for data encapsulation request
      • Introduces the alipayFormData constructor to create the form required by the site to pay forconst AlipayFormData = require('alipay-sdk/lib/form').default;
      • The createOrder package and the detailed code are as follows:
      // Write a function that creates a payment order and asynchronously waits for execution
      async function createOrder(goods) {
          let method = 'alipay.trade.page.pay'; // Unified receiving order and payment page interface
          // Public parameters can be passed based on service requirements
          // let params = {
          // app_id: '2016101000654289', // Application ID
          // method: method, // call the interface
          // format: 'JSON', // returns data
          // charset: 'utF-8 ', // character encoding
          Sign_type: 'RSA2', // Check type
          // timestamp: getFormatDate()
          // version: '1.0', // version
          // }
          // A set of parameters according to the API documentation provided by the official
          let bizContent = {
              out_trade_no: Date.now(), // Generate an order number based on the timestamp,
              product_code: 'FAST_INSTANT_TRADE_PAY'.// Product code is currently only supported
              total_amount: goods.cost, // Commodity prices
              subject: goods.goodsName, // Product name
              timeout_express: '5m'.// The timeout period
              passback_params: JSON.stringify(goods.pack_params), // A parameter that will be returned, which can be used to customize the product information for final notification
          }
          const formData = new AlipayFormData(); // Get an instantiated object
          formData.addField('returnUrl'.'http://jiangck.com:9999/payresult'); // The client will jump back to the address after successful payment
          formData.addField('notifyUrl'.'http://jiangck.com:9999/notify.html'); // Alipay will asynchronously notify the callback address after the payment is successful, which can only be received on the public IP address
          formData.addField('bizContent', bizContent); // Add the required set of parameters to the form
      
          // Asynchronously send an order generation request to Alipay. The second parameter is a public parameter. If it is not needed, pass in an empty object
          const result = await alipay.exec(method, {}, {
              formData: formData
          });
          // Return the result information of the order
          return result;
      }
      Copy the code
    • Expose the method for generating orders
      module.exports = {
          createOrder: createOrder
      }
      Copy the code
  • Create checksign.js check module
    • Attestation is in when to pay for success, pay treasure to asynchronous setting good callback address to the server to send a post request, to tell us the payment information of server users and server end is based on the asynchronous notification logic to handle business, rather than rely on alipay synchronous jump, and after paying treasure to send the asynchronous notification request, The server needs to do a verification check, this step is necessary, because money transactions must be rigorous, must verify the authenticity of the requested information. Logical processing can only be done after it is legal. The packaged verification function is also a tool based on alipaySDK, which is only used for convenient invocation. The code is as follows:
    const path = require('path');
    
    // For notification verification
    ------ Configure the Alipay SDK environment
    / / import the SDK
    const AlipaySDK = require("alipay-sdk").default;
    // Import the configuration
    const alipayConfig = require(path.join(__dirname, './alipay_config.js'));
    / / initialization
    const alipaySdk = new AlipaySDK(alipayConfig.AlipayBaseConfig);
    
    async function checkNotify(obj) {
        const result = await alipaySdk.checkNotifySign(obj);
        return result;
    }
    
    module.exports = checkNotify;
    Copy the code
  • Create the mysql.js module, which is used to encapsulate the storage work of the database
    • The code is as follows:
    /* This custom module is used to add and query mysql database orders */
    
    // Import the mysql module
    const mysql = require('mysql');
    
    / / configure the mysql
    const mysqlConfig = {
        host: 'localhost'.// Database host name
        port: '3306'./ / the port number
        user: 'root'./ / user name
        password: '123456'./ / password
        database: 'alipay'.// Database name
    }
    
    // encapsulate the query function
    function selectSql(sqlstr,callback) {
        // Establish a database connection
        let sql = mysql.createConnection(mysqlConfig);
        let result = null;
        if (sql) {
            sql.query(sqlstr, callback);
            // Close the database connectionsql.end(); }}// Encapsulate add function
    function addSql(sqlstr,callback) {
        return selectSql(sqlstr,callback);
    }
    
    // Expose two database operation methods
    module.exports = {
        selectSql: selectSql,
        addSql: addSql
    }
    Copy the code
  • Create server.js to create an HTTP server, and do the request processing code for each interface as follows:
    const path = require("path");
    const bp = require('body-parser');
    // Introduce custom mysql tools
    const mysql = require(path.join(__dirname, './mysql.js'));
    / / into the express
    const express = require('express');
    // Get the Express instance object
    let app = express();
    
    // Set up managed static resources
    app.use(express.static(path.join(__dirname, './public')));
    // Process the POST request parameters
    app.use(bp.urlencoded({
        extended: false
    }));
    
    // The front end responds to the data object to create the order
    app.get('/payinfo', (req, res) => {
        let data = req.query;
        // Make a simple commodity judgment
        if (data && (data.goodsName === 'Daviosaur' || data.goodsName === 'Broad ice' || data.goodsName === 'spirits' || data.goodsName === 'QQB') && data.count && data.cost) {
            res.send(Object.assign(data, {
                code: 200,})); }else {
            res.setHeader('content-type'.'application/javascript');
            res.send('Wrong message, please try again!!' ) '); }})// Get the custom module to create the order
    const createOrder = require(path.join(__dirname, './createOrder.js')).createOrder;
    // Get the validation custom module
    const checkSign = require(path.join(__dirname, './checkSign.js'));
    
    // Generate an order request
    app.post('/createOrder', (req, res) => {
        console.log(req.body.price);
        req.body.pack_params = {
            payName: req.body.payName,
            goodsName: req.body.goodsName,
            price: req.body.price,
            count: req.body.count,
            cost: req.body.cost,
        }
        async function asyncCreate() {
            const result = await createOrder(req.body);
            res.send(result);
        }
        asyncCreate();
    });
    
    // Display the payment information
    app.get('/payresult', (req, res) => {
        let htmlStr = ' ';
        htmlStr += `<p>` + 'Merchant Order No.' + ':' + req.query.out_trade_no + '</p>'
        htmlStr += `<p>` + 'Alipay Transaction Order Number' + ':' + req.query.trade_no + '</p>'
        htmlStr += `<p>` + 'Transaction Amount' + ':' + req.query.total_amount + 'RMB < / p >'
        htmlStr += `<p>` + 'Trading time' + ':' + req.query.timestamp + 'RMB < / p >'
        htmlStr += '

    Payment successful!!

    '
    res.send(htmlStr); }) app.post('/notify.html', (req, res) => { // Output the verification result async function checkResult(postData) { let result = await checkSign(postData); if (result) { // console.log(' Order paid successfully!! Please do something ') // console.log(req.body); let data = req.body; let goods = JSON.parse(data.passback_params); let sqlStr = ` insert into order_list value("${data.out_trade_no}","${data.trade_no}","${goods.goodsName}", ${goods.price}.${goods.count}.${data.total_amount}", "Payment successful ","${goods.payName}"); `; // If alipay succeeds in processing, alipay will always send asynchronous notifications periodically res.end('success'); mysql.addSql(sqlStr) } } checkResult(req.body); }) // Query order interface app.get('/getorder', (req, res) => { mysql.selectSql('select * from order_list', (err, result) => { result = Object.assign({ code: 200.msg: 'Obtain success'.list: JSON.stringify(result), }) res.send(result); }); }) app.listen(9999, () = > {console.log('server start with 9999... '); }) Copy the code
  • Public Static resource
    • Static resources are only used by the front end to show the operation of the client. Specific files can be accessed from github open source Demo, which contains a dump file of The Alipay. SQL database, or can be created by itself.

conclusion

  • The above steps is a alipay site payment interface call Demo simple development.
  • The problems encountered during the development process are as follows:
    • Public key configuration in SDK configuration, it is clear to fill in alipay public key, not application public key
    • The secret key algorithm has to correspond to RSA and RSA2 and you have to figure out, what’s the encryption
    • Check the failure to check the encryption algorithm, alipay public key, use private key/public key encryption type
    • After passing the verification, you must want to pay the string “success” of the response success information, otherwise it will always be notified asynchronously, resulting in multiple business processing.
  • This test DEMO has been open source Github, you can click me to get the test DEMO. If you are helpful, please Star under O(∩_∩)O.
  • This is also my first payment test demo, there will be bugs, I will add more interface test demo and step by step improvement, if there is any problem can leave a message to communicate with oh.