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


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

    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网站时,会自动读取我的证书,
        
        • 1
      • 和目标网站不符,会报错),所以这里需要绕过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];
         }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11

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

      private static void setPostParams(HttpPost httpPost, Map 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 params) {
        return doPost(url, params, DEFAULT_CHARSET);
        }
        /
        *
      • post请求
      • @param url 请求地址
      • @param params 请求参数
      • @param charset 字符编码
      • @return 响应正文
        */
        public static String doPost(String url, Map 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> 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

  • 相关阅读:
    计算机网络入门基础篇——应用层
    在Spring Boot应用中实现阿里云短信功能的整合
    如何使用企业内容管理 (ECM) 软件工具节约时间和金钱,提高企业效率和效益
    indiegogo众筹
    JAVA多线程FutureTask作用
    Git基础
    SLAM从入门到精通(里程计的计算)
    ChatGPT:理解HTTP请求数据格式:JSON、x-www-form-urlencoded和form-data
    员工脉搏/脉动调查完整指南
    如何使用mysqldump快速复制Mysql数据库操作实践
  • 原文地址:https://blog.csdn.net/ywtech/article/details/133276965