医保移动支付和接口对接开发

医保移动支付和接口对接开发

1 · 医保移动支付开发注意事项。
2 · HTTP 基础知识: 回顾 HTTP 请求的基本结构和工作原理,包括请求方法、请求头、请求体等。
3 · 数据格式处理: 探讨如何正确处理不同数据格式(如 JSON、XML)的请求和响应。
4 · 错误处理策略: 研究异常情况下的最佳实践,包括重试策略、超时处理和错误状态码处理。
5 · 性能优化: 提供性能优化技巧,减少请求延迟和提高吞吐量。
6 · 第三方服务认证: 学习如何进行认证和授权,以确保只有授权的请求可以访问第三方服务。(服务接口提供方)
7 · 安全性: 讲解如何保护 HTTP 请求和响应,防止潜在的安全漏洞。(服务接口提供方)
8 · 日志和监控: 了解如何记录请求和响应信息,以及如何设置监控来追踪系统的健康状况

1医保移动支付开发注意事项:

1.1微信医保移动支付关注文档:
https://docs.qq.com/doc/DV1J6ZVB6eHZ3amxK
1.2用户授权接入文档见链接:
用户授权接入文档(医保信息授权)(payAuthNo版本) https://docs.qq.com/doc/DV3JYRG1xelhKTWdz
1.3对接移动医疗平台接口文档见链接:
对接移动医疗平台接口文档_国家局v4.0 https://docs.qq.com/doc/DV3lxV3hSbXFudVBE

2 · HTTP基础知识: 回顾 HTTP1.1 请求的基本结构和工作原理,包括请求方法、请求头、请求体等。
2.1 请求例子:
curl --location --request POST ‘https://hlwyy.songjianghealth.com/zsyy/insuranceWx/refundInsurance?refund_key=8e6458f38c2ca66215c94a42c517ddfd’
–header ‘Content-Type: application/json’
–data-raw ’ {
“appRefdSn”: “ORD310100202309221504550007718”,
“appRefdTime”: “20230529210946”,
“cashRefdAmt”: “1.00”,
“ecToken”: “”,
“expContent”: “”,
“fundRefdAmt”: “0”,
“outTradeNo”: “0”,
“payAuthNo”: “ORD310100202309221504550007718”,
“payOrdId”: “ORD310100202309221504550007718”,
“payWay”: “01”,
“psnAcctRefdAmt”: “1.00”,
“refdType”: “HI”,
“totlRefdAmt”: “15.54”
}’

2.2 请求客户端 httpClient

https://hc.apache.org/httpcomponents-client-4.5.x/current/tutorial/html/connmgmt.html

package cn.google.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.
;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.*;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**

  • HttpClient工具类

  • @author

  • @date 2023-09-18 17:12
    /
    @Slf4j
    public class HttpClientUtil {
    /
    *

    • 超时时间
      /
      private static final int TIMEOUT = 30 * 1000;
      /
      *
    • 最大连接数
      /
      private static final int MAX_TOTAL = 200;
      /
      *
    • 每个路由的默认最大连接数
      /
      private static final int MAX_PER_ROUTE = 40;
      /
      *
    • 目标主机的最大连接数
      /
      private static final int MAX_ROUTE = 100;
      /
      *
    • 访问失败时最大重试次数
      */
      private static final int MAX_RETRY_TIME = 5;

    private static CloseableHttpClient httpClient = null;
    private static final Object SYNC_LOCK = new Object();
    private static final String DEFAULT_CHARSET = “UTF-8”;

    private static void config(HttpRequestBase httpRequestBase) {
    //配置请求的超时时间
    RequestConfig requestConfig = RequestConfig.custom()
    .setConnectionRequestTimeout(TIMEOUT)
    .setConnectTimeout(TIMEOUT)
    .setSocketTimeout(TIMEOUT)
    .build();
    httpRequestBase.setConfig(requestConfig);
    }

    /**

    • 获取HttpClient对象
      /
      private static CloseableHttpClient getHttpClient(String url) throws NoSuchAlgorithmException, KeyManagementException {
      String hostName = url.split(“/”)[2];
      int port = 80;
      if (hostName.contains(“:”)) {
      String[] attr = hostName.split(“:”);
      hostName = attr[0];
      port = Integer.parseInt(attr[1]);
      }
      if (httpClient == null) {
      synchronized (SYNC_LOCK) {
      if (httpClient == null) {
      httpClient = createHttpClient(MAX_TOTAL, MAX_PER_ROUTE, MAX_ROUTE, hostName, port);
      }
      }
      }
      return httpClient;
      }
      /
      *
    • 创建HttpClient对象
      */
      private static CloseableHttpClient createHttpClient(int maxTotal, int maxPerRoute, int maxRoute,
      String hostName, int port) throws KeyManagementException, NoSuchAlgorithmException {
      PlainConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
      SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(createIgnoreVerifySSL());
      Registry registry = RegistryBuilder.create()
      .register(“http”, plainsf)
      .register(“https”, sslsf)
      .build();
      PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
      //增加最大连接数
      cm.setMaxTotal(maxTotal);
      //增加每个路由的默认最大连接
      cm.setDefaultMaxPerRoute(maxPerRoute);
      //增加目标主机的最大连接数
      cm.setMaxPerRoute(new HttpRoute(new HttpHost(hostName, port)), maxRoute);
      //请求重试
      HttpRequestRetryHandler httpRequestRetryHandler = (exception, executionCount, context) -> {
      //若重试5次,放弃
      if (executionCount >= MAX_RETRY_TIME) {
      return false;
      }
      //若服务器丢掉了连接,那就重试
      if (exception instanceof NoHttpResponseException) {
      return true;
      }
      //不重试SSL握手异常
      if (exception instanceof SSLHandshakeException) {
      return false;
      }
      //超时
      if (exception instanceof InterruptedIOException) {
      return false;
      }
      //目标服务器不可达
      if (exception instanceof UnknownHostException) {
      return false;
      }
      //SSL握手异常
      if (exception instanceof SSLException) {
      return false;
      }
      HttpClientContext clientContext = HttpClientContext.adapt(context);
      HttpRequest request = clientContext.getRequest();
      //若请求时幂等的,就再次尝试
      return !(request instanceof HttpEntityEnclosingRequest);
      };
      return HttpClients.custom().setConnectionManager(cm)
      .setRetryHandler(httpRequestRetryHandler)
      .build();
      }

    /**

    • HttpClient配置SSL绕过https证书(因为我的网站是有https证书的,所以在访问https网站时,会自动读取我的证书,
      
    • 和目标网站不符,会报错),所以这里需要绕过https证书
      */
      private static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
      SSLContext sslContext = SSLContext.getInstance(“SSLv3”);
      // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
      X509TrustManager trustManager = new X509TrustManager() {
      @Override
      public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

       }
      
       @Override
       public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
      
       }
      
       @Override
       public X509Certificate[] getAcceptedIssuers() {
           return new X509Certificate[0];
       }
      

      };
      sslContext.init(null, new TrustManager[] {trustManager}, null);
      return sslContext;
      }

    private static void setPostParams(HttpPost httpPost, Map<String, Object> params) {
    List nameValuePairs = new ArrayList<>();
    params.forEach((key, value) -> nameValuePairs.add(new BasicNameValuePair(key, value.toString())));
    try {
    httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEFAULT_CHARSET));
    } catch (UnsupportedEncodingException e) {
    e.printStackTrace();
    }
    }
    /**

    • post请求,默认编码格式为UTF-8
    • @param url 请求地址
    • @param params 请求参数
    • @return 响应正文
      /
      public static String doPost(String url, Map<String, Object> params) {
      return doPost(url, params, DEFAULT_CHARSET);
      }
      /
      *
    • post请求
    • @param url 请求地址
    • @param params 请求参数
    • @param charset 字符编码
    • @return 响应正文
      */
      public static String doPost(String url, Map<String, Object> params, String charset) {
      HttpPost httpPost = new HttpPost(url);
      config(httpPost);
      setPostParams(httpPost, params);
      return getResponse(url, httpPost, charset);
      }

    /**

    • get请求,默认编码UTF-8
    • @param url 请求地址
    • @return 响应正文
      /
      public static String doGet(String url) {
      return doGet(url, DEFAULT_CHARSET);
      }
      /
      *
    • get请求
    • @param url 请求地址
    • @param charset 字符编码
    • @return 响应正文
      */
      public static String doGet(String url, String charset) {
      HttpGet httpGet = new HttpGet(url);
      config(httpGet);
      return getResponse(url, httpGet, charset);
      }

    /**

    • 发起请求,获取响应
    • @param url 请求地址
    • @param httpRequest 请求对象
    • @param charset 字符编码
    • @return 响应正文
      */
      private static String getResponse(String url, HttpRequestBase httpRequest, String charset) {
      CloseableHttpResponse response = null;
      try {
      response = getHttpClient(url).execute(httpRequest, HttpClientContext.create());
      HttpEntity httpEntity = response.getEntity();
      String result = EntityUtils.toString(httpEntity, charset);
      EntityUtils.consume(httpEntity);
      return result;
      } catch (IOException | NoSuchAlgorithmException | KeyManagementException e) {
      log.error(“网络访问异常!”, e);
      } finally {
      try {
      if (response != null) {
      response.close();
      }
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      return null;
      }

}
2.3 请求客户端restTemplate.

package cn.ucmed.zsyy.common.config.restTemplate;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.*;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**

  • @author ucmed

  • @since 2022/1/4 16:13
    */
    @Slf4j
    @Configuration
    public class RestTemplateConfig {

    @Value(“ h t t p . c o n n e c t i o n . m a x " ) p r i v a t e i n t c o n n e c t i o n M a x ; @ V a l u e ( " {http.connection.max}") private int connectionMax; @Value(" http.connection.max")privateintconnectionMax;@Value("{http.connection.route.max}”)
    private int connectionRouteMax;
    @Value(“ h t t p . c o n n e c t . t i m e o u t " ) p r i v a t e i n t c o n n e c t T i m e o u t ; @ V a l u e ( " {http.connect.timeout}") private int connectTimeout; @Value(" http.connect.timeout")privateintconnectTimeout;@Value("{http.socket.timeout}”)
    private int socketTimeout;
    @Value(“${http.request.timeout}”)
    private int requestTimeout;

    @Bean
    public RestTemplate getRestTemplate() {
    RestTemplate restTemplate = new RestTemplate(httpComponentsClientHttpRequestFactory());
    List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters(); Iterator

3 · 接口数据格式处理: 探讨如何正确处理不同数据格式(如 JSON、XML)的请求和响应。

3.1 利用excel表格生成javaBean代码
代码及文档: 使用文档拷贝,入参 出参处理。 代码注释包含 属性描述 说明备注 是否必填等

3.2 出入参数业务异常统一处理.

String xmlReturnStr = centerHospitalHttpService.postRequestHis(ShanghaiSongCenterHospitalHttpService.HIS_URL,
xmlString);
HisBaseBeanResult hisResult = new HisBaseBeanResult<>();
//异常统一处理
hisResult.builderBeanData(xmlReturnStr, ClinicDetailHisResult.class);

3.3 禁止未知异常,推荐返回his接口的业务his异常信息

String xmlString = objToxml(xmlBody);
log.warn(“xmlString ::{}”, xmlString);
String xmlReturnStr = centerHospitalHttpService.postRequestHis(ShanghaiSongCenterHospitalHttpService.HIS_URL,
xmlString);
HisBaseBeanResult hisResult = new HisBaseBeanResult<>();
hisResult.builderBeanData(xmlReturnStr, ClinicDetailHisResult.class);
ClinicDetailHisResult items = hisResult.getBeanData();

4 · 熔断错误处理策略: 研究异常情况下的最佳实践,包括重试策略、超时处理和错误状态码处理。

4.1 什么是接口熔断.(容错)

系统A调⽤B,⽽B调⽤C,这时如果C出现故障,则此时调⽤B的⼤量线程资源阻塞,慢慢的B的线程数量持续增加直到CPU耗尽到100%,整体微服务不可⽤,这时就需要对不可⽤的服务进⾏隔离.

系统所依赖的服务的稳定性对系统的影响⾮常⼤,⽽且还有很多不确定因素引起雪崩,如⽹络连接中断,服务宕机等

https://blog.csdn.net/ywtech/article/details/132626613

4.2如何熔断的原理

4.3熔断保护-社区生态有哪些方案

Sentinel 与 Hystrix、Resilience4j

4.4 熔断保护系统实践.( 熔断 降级 并发限流,重试)

5 性能优化: 提供性能优化技巧,减少请求延迟和提高吞吐量。

5.1 禁止使用 new RestTemplate()

5.2 推荐使用连接连接池 forest http 客户端

6 · 第三方服务认证: 学习如何进行认证和授权,以确保只有授权的请求可以访问第三方服务。(服务接口提供方)

7 · 安全性: 讲解如何保护 HTTP 请求和响应,防止潜在的安全漏洞。(服务接口提供方)

8 · 日志和监控: 了解如何记录请求和响应信息,以及如何设置监控来追踪系统的健康状况

Skywalking

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值