The company I work for is developing a unified payment platform. Due to the company’s business needs, it needs access to multiple third-party payments. In order to further think about the payment platform, I sorted it out.

The component patterns

Since the company’s business covers many regions, it needs to provide a variety of payment channels to meet the business development. Therefore, the designed payment platform needs access to a variety of third-party payment channels, such as: Wechat Pay, Alipay payment, card payment, Xunlink and so on, as we all know, each third-party payment, has its own set of external API, the official has a set of SDK to implement these apis, how should we organize these apis?

Due to the third party payment channel will change along with the development of the business, so the organization needs without affecting the SDK payment platform overall architecture under the premise of flexible plug, here I use the idea of component, and will pay the API into various components pay components, refund components, components, billing, order exception handling components, etc. In this way, when introducing a third-party payment SDK, the required API can be flexibly added to the component. The architecture design is as follows:

Unified callback and asynchronous distribution processing

A feature of third-party payment is that there will be a callback function for payment and refund after successful payment and refund. The purpose is as follows: 1. The merchant platform can verify the legality of the order by itself, for example: To prevent the client from maliciously tampering with the amount and other parameters during the payment, the order will be in the payment state after the payment is successful and need to wait for the third-party callback. If the payment amount and the order amount are found to be incorrect after receiving the callback check, we can change the order state to failed to prevent the loss of funds. 2: Through callbacks we can handle the business logic of our own systems, distribution of goods, etc. The idea of callback is to ensure the final consistency of the data, so we do not need to verify the correctness of the parameters when we initiate payment. We only need to verify the correctness when we call back. Then how should we set the callback of payment platform.

Because the payment need to access multiple third-party payment platform, if the third party payment each set a callback address, so there will be multiple callback address, because the callback API must be exposed to accept the third callback, so there will be a security issue, we must in the API outer set security filters, so we need a unified API callback, Unified security check, and then a layer of distribution.

The distribution mechanism is RabbitMq. If mq is used for distribution, how can the verification result be returned to the third party in real time? Here are some thoughts on the pullback:

1. The system is based on the Spring Boot microservice architecture. Services communicate through Http. If Http is used to distribute messages, the real-time return of messages can be guaranteed. 2. Due to the third-party payment if receive false response, will again in the next period of time a callback requests, the aim is to guarantee the success rate of the callback for third-party payment, there is nothing wrong with it, but for merchant payment platform, maybe it is the design of a more pit dad, do you think about it, Suppose you have an order to pay for the malicious tampering with the amount, the callback check fails, return false to third-party payment, the third-party payment will repeat send back, no matter how many times to send back, will check fails, it’s an extra unnecessary interactions, here, of course, you can also use idempotent for processing, the following is the application scenarios of WeChat pay callback:

Based on the above two thinking, I don’t think return false to the third-party payment is necessary, for the sake of the robustness of the system, I used the message queue for asynchronous distributed, payment platform directly after receiving callback request returns true, then you might have to ask you a question, if the check fails, the return true at this time, however, there is no problem? First of all, in the case of verification failure, the order must be in the state of payment failure, and the purpose of returning true is to reduce unnecessary remote interaction with the third-party payment.

Since Mq persists messages to disk, the biggest benefit of message queuing for distribution is to review messages in the message queue for troubleshooting, and message queuing can be used for peak traffic clipping at peak times.

The following is an architecture diagram for unified callback and distribution:

Aggregate pay

Payment platform polymerization a wide variety of third-party payment, so need to do a lot of adaptation work request layer, in order to meet the needs of a variety of payment, you might think, directly to the adapter there to add a few lines if the else don’t have to, to do so is no problem, can also meet the needs of a variety of payment, but if you add a third party payment? You can only add multiple else conditions to the existing method, which will cause the request layer code to change as the business evolves, making the code extremely inelegant and not easy to maintain. In this case, we can use the strategy mode to eliminate the if else code. When we add a third party payment, We just need to create a new Strategy class with the following structure:

The request processing

Since the payment platform involves funds, all kinds of payment requests and returns, and abnormal records are extremely important in a payment platform, we need to record every payment request record for subsequent troubleshooting.

Based on this, we design a handler layer before requesting third-party payment. All requests must be processed by the Handler layer. The handler core method is as follows:

public K handle(T t) {
  K k;
  try {
    before(t);
    k = execute(t);
    after(k);
  } catch (Exception e) {
    exception(t, e);
  }
  return k;
}
protected abstract void before(T t);
protected abstract void after(K k);
protected abstract void exception(T t, Exception exception);

Handler layer uses the template mode, not only can realize the log record, but also can realize a variety of processing methods, such as request monitoring, message push and so on, to achieve the high scalability of the Handler layer