網站怎麼接入微信掃碼支付?

来源:https://www.cnblogs.com/deyo/archive/2023/06/20/17495203.html
-Advertisement-
Play Games

# 第01章-準備工作 ## 1、微信支付產品介紹 參考資料:[產品中心 - 微信支付商戶平臺 (qq.com)](https://pay.weixin.qq.com/static/product/product_index.shtml#payment_product) 付款碼支付、JSAPI支付、 ...


第01章-準備工作

1、微信支付產品介紹

參考資料:產品中心 - 微信支付商戶平臺 (qq.com)

付款碼支付、JSAPI支付、小程式支付、Native支付、APP支付、刷臉支付

1.1、付款碼支付

用戶展示微信錢包內的“付款碼”給商家,商家掃描後直接完成支付,適用於線下麵對面收銀的場景。

1.2、JSAPI支付

  • 線下場所:商戶展示一個支付二維碼,用戶使用微信掃描二維碼後,輸入需要支付的金額,完成支付。
  • 公眾號場景:用戶在微信內進入商家公眾號,打開某個頁面,選擇某個產品,完成支付。
  • PC網站場景:在網站中展示二維碼,用戶使用微信掃描二維碼,輸入需要支付的金額,完成支付。

特點:用戶在客戶端輸入支付金額

1.3、小程式支付

在微信小程式平臺內實現支付的功能。

1.4、Native支付

Native支付是指商戶展示支付二維碼,用戶再用微信“掃一掃”完成支付的模式。這種方式適用於PC網站。

特點:商家預先指定支付金額

1.5、APP支付

商戶通過在移動端獨立的APP應用程式中集成微信支付模塊,完成支付。

1.6、刷臉支付

用戶在刷臉設備前通過攝像頭刷臉、識別身份後進行的一種支付方式。

2、介面版本

微信支付企業主流的API版本有v2和v3,課程中我們使用微信支付APIv3。

V2和V3的比較

image-20230227201412325

相比較而言,APIv2比APIv3安全性更高,但是APIv2中有一些功能在APIv3中尚未完整實現,具體參考如下API字典頁面:API字典概覽 | 微信支付商戶平臺文檔中心 (qq.com)

image-20230318134648306

3、接入指引

3.1、獲取開發參數

如果需要獨立申請和開通微信支付功能,可以參考如下官方文檔。開通微信支付後,才能獲取相關的開發參數以及商戶公鑰和商戶私鑰文件。

參考資料:微信支付接入指引 - 微信支付商戶平臺 (qq.com)

3.2、配置開發參數

service-order服務的resources目錄中創建wxpay.properties

這個文件定義了在“接入指引”的步驟中我們提前準備的微信支付相關的參數,例如商戶號、APPID、API秘鑰等等

# 微信支付相關參數
wxpay:
  mch-id: 1558950191 #商戶號
  mch-serial-no: 34345964330B66427E0D3D28826C4993C77E631F # 商戶API證書序列號
  private-key-path: D:/project/yygh/cert/apiclient_key.pem # 商戶私鑰文件
  api-v3-key: UDuLFDcmy5Eb6o0nTNZdu6ek4DDh4K8B # APIv3密鑰
  appid: wx74862e0dfcf69954 # APPID
  notify-url: https://7d92-115-171-63-135.ngrok.io/api/order/wxpay/payment/notify # 接收支付結果通知地址
  notify-refund-url: http://agxnyzl04y90.ngrok.xiaomiqiu123.top/api/order/wxpay/refunds/notify # 接收退款結果通知地址

3.3、複製商戶私鑰

將商戶私鑰文件複製到配置文件指定的目錄下:

資料:資料>微信支付>商戶證書>apiclient_key.pem

private-key-path: D:/project/yygh/cert/apiclient_key.pem # 商戶私鑰文件

3.4、證書密鑰使用說明(瞭解)

參考文檔:APIv3證書與密鑰使用說明

一個完整的請求和響應的流程:

  • 商戶使用商戶私鑰對請求進行簽名,發送給微信支付平臺,平臺使用商戶公鑰進行簽名驗證。
  • 微信支付平臺使用平臺私鑰對響應進行簽名,商戶使用微信支付平臺公鑰對響應進行驗簽。

img

第02章-訂單支付

1、微信支付平臺證書的獲取

1.1、引入SDK

參考文檔:SDK&工具

我們可以使用官方提供的 SDK wechatpay-java

在service-order微服務中添加依賴:

<!--微信支付APIv3-->
<dependency>
  <groupId>com.github.wechatpay-apiv3</groupId>
  <artifactId>wechatpay-java</artifactId>
  <version>0.2.6</version>
</dependency>

1.2、讀取支付參數

在config 包中 創建 WxPayConfig.java

package com.atguigu.syt.order.config;

@Configuration
@PropertySource("classpath:wxpay.properties") //讀取配置文件
@ConfigurationProperties(prefix="wxpay") //讀取wxpay節點
@Data
public class WxPayConfig {

    // 商戶號
    private String mchId;

    // 商戶API證書序列號
    private String mchSerialNo;

    // 商戶私鑰文件
    private String privateKeyPath;

    // APIv3密鑰
    private String apiV3Key;

    // APPID
    private String appid;
    
    // 接收支付結果通知地址
    private String notifyUrl;
    
    // 接收退款結果通知地址
    private String notifyRefundUrl;
   
}

1.3、自動更新微信支付平臺證書

在 API 請求過程中,客戶端需使用微信支付平臺證書,驗證伺服器應答的真實性和完整性。我們使用自動更新平臺證書的配置類 RSAAutoCertificateConfig。每個商戶號只能創建一個 RSAAutoCertificateConfig

WxPayConfig中添加如下方法:

/**
     * 獲取微信支付配置對象
     * @return
     */
@Bean
public RSAAutoCertificateConfig getConfig(){

    return new RSAAutoCertificateConfig.Builder()
        .merchantId(mchId)
        .privateKeyFromPath(privateKeyPath)
        .merchantSerialNumber(mchSerialNo)
        .apiV3Key(apiV3Key)
        .build();
}

RSAAutoCertificateConfig 通過 RSAAutoCertificateProvider 自動下載微信支付平臺證書。 同時,RSAAutoCertificateProvider 會啟動一個後臺線程,定時更新證書(目前設計為60分鐘),以實現證書過期時的新老證書平滑切換。

常見錯誤:引入商戶私鑰後如果項目無法啟動,則需要升級JDK版本,並重新配置idea編譯和運行環境到最新版本的JDK。建議升級到1.8.0_300以上

img

2、生成支付二維碼

2.1、Native支付流程

參考文檔:業務流程時序圖

img

2.2、Controller

在service-order中創建FrontWXPayController

package com.atguigu.syt.order.controller.front;

@Api(tags = "微信支付介面")
@RestController
@RequestMapping("/front/order/wxpay")
public class FrontWXPayController {

    @Resource
    private WxPayService wxPayService;

    @Resource
    private AuthContextHolder authContextHolder;

    @ApiOperation("獲取支付二維碼url")
    @ApiImplicitParam(name = "outTradeNo",value = "訂單號", required = true)
    @GetMapping("/auth/nativePay/{outTradeNo}")
    public Result<String> nativePay(@PathVariable String outTradeNo, HttpServletRequest request, HttpServletResponse response) {

        //校驗用戶登錄狀態
        authContextHolder.checkAuth(request, response);

        String codeUrl = wxPayService.createNative(outTradeNo);
        return Result.ok(codeUrl);
    }
}

2.3、Service

SDK參考代碼:wechatpay-java/NativePayServiceExample.java at main · wechatpay-apiv3/wechatpay-java · GitHub

image-20230228224937529

具體代碼示例如下:

image-20230228225031308

Native下單API參數參考:Native下單API

介面:OrderInfoService

/**
 * 根據訂單號獲取訂單
 * @param outTradeNo
 * @return
 */
OrderInfo selectByOutTradeNo(String outTradeNo);

實現:OrderInfoServiceImpl

@Override
public OrderInfo selectByOutTradeNo(String outTradeNo) {
    LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(OrderInfo::getOutTradeNo, outTradeNo);
    return baseMapper.selectOne(queryWrapper);
}

介面:WxPayService

package com.atguigu.syt.order.service;

public interface WxPayService {

    /**
     * 獲取支付二維碼utl
     * @param outTradeNo
     * @return
     */
    String createNative(String outTradeNo);
}

實現:WxPayServiceImpl

package com.atguigu.syt.order.service.impl;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Resource
    private RSAAutoCertificateConfig rsaAutoCertificateConfig;

    @Resource
    private WxPayConfig wxPayConfig;

    @Resource
    private OrderInfoService orderInfoService;

    @Override
    public String createNative(String outTradeNo) {

        // 初始化服務
        NativePayService service = new NativePayService.Builder().config(rsaAutoCertificateConfig).build();

        // 調用介面
        try {

            //獲取訂單
            OrderInfo orderInfo = orderInfoService.selectByOutTradeNo(outTradeNo);

            PrepayRequest request = new PrepayRequest();
            // 調用request.setXxx(val)設置所需參數,具體參數可見Request定義
            request.setAppid(wxPayConfig.getAppid());
            request.setMchid(wxPayConfig.getMchId());

            request.setDescription(orderInfo.getTitle());
            request.setOutTradeNo(outTradeNo);
            request.setNotifyUrl(wxPayConfig.getNotifyUrl());

            Amount amount = new Amount();
            //amount.setTotal(orderInfo.getAmount().multiply(new BigDecimal(100)).intValue());
            amount.setTotal(1);//1分錢
            request.setAmount(amount);
            // 調用介面
            PrepayResponse prepayResponse = service.prepay(request);

            return prepayResponse.getCodeUrl();

        } catch (HttpException e) { // 發送HTTP請求失敗
            // 調用e.getHttpRequest()獲取請求列印日誌或上報監控,更多方法見HttpException定義
            log.error(e.getHttpRequest().toString());
            throw new GuiguException(ResultCodeEnum.FAIL);
        } catch (ServiceException e) { // 服務返回狀態小於200或大於等於300,例如500
            // 調用e.getResponseBody()獲取返回體列印日誌或上報監控,更多方法見ServiceException定義
            log.error(e.getResponseBody());
            throw new GuiguException(ResultCodeEnum.FAIL);
        } catch (MalformedMessageException e) { // 服務返回成功,返回體類型不合法,或者解析返回體失敗
            // 調用e.getMessage()獲取信息列印日誌或上報監控,更多方法見MalformedMessageException定義
            log.error(e.getMessage());
            throw new GuiguException(ResultCodeEnum.FAIL);
        }
    }
}

可見,使用 SDK 並不需要計算請求簽名和驗證應答簽名。

3、前端整合

3.1、api

創建api/wxpay.js

import request from '~/utils/request'
export default {
  //獲取支付二維碼url
  nativePay(outTradeNo) {
    return request({
      url: `/front/order/wxpay/auth/nativePay/${outTradeNo}`,
      method: 'get'
    })
  },
}

3.2、修改show.vue

引入api

import wxpayApi from '~/api/wxpay'

添加data數據

codeUrl: null, //微信支付二維碼
isPayShow: false, //不顯示登錄二維碼組件
payText: '支付'

修改按鈕

將
<div class="v-button" @click="pay()">支付</div>
修改為
<div class="v-button" @click="pay()">{{payText}}</div>

添加方法

//支付
pay() {
    //防止重覆提交
    if(this.isPayShow) return
    this.isPayShow = true
    this.payText = '支付中.....'

    //顯示二維碼
    wxpayApi.nativePay(this.orderInfo.outTradeNo).then((response) => {
        this.codeUrl = response.data
        this.dialogPayVisible = true
    })
},

//關閉對話框
closeDialog(){
    //恢復支付按鈕
    this.isPayShow = false
    this.payText = '支付'
}

用二維碼組件替換img圖片

<img src="二維碼鏈接" alt="" />

替換成

<qriously :value="codeUrl" :size="220"/>

img

第03章-查詢支付結果

1、支付查單

參考文檔:微信支付查單介面

商戶可以主動調用微信支付查單介面,同步訂單狀態。

調用查詢訂單介面,如果支付成功則更新訂單狀態添加交易記錄,如果支付尚未成功則輪詢查單

1.1、更新訂單狀態

OrderInfoService介面

/**
     * 根據訂單號更新訂單狀態
     * @param outTradeNo
     * @param status
     */
void updateStatus(String outTradeNo, Integer status);

OrderInfoServiceImpl實現

@Override
public void updateStatus(String outTradeNo, Integer status) {

    LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(OrderInfo::getOutTradeNo, outTradeNo);

    OrderInfo orderInfo = new OrderInfo();
    orderInfo.setOrderStatus(status);
    baseMapper.update(orderInfo, queryWrapper);
}

1.2、添加交易記錄

PaymentInfoService介面

/**
     * 保存交易記錄
     * @param orderInfo
     * @param transaction
     */
void savePaymentInfo(OrderInfo orderInfo, Transaction transaction);

實現:PaymentInfoServiceImpl

@Override
public void savePaymentInfo(OrderInfo orderInfo, Transaction transaction) {

    PaymentInfo paymentInfo = new PaymentInfo();
    paymentInfo.setOrderId(orderInfo.getId());
    paymentInfo.setPaymentType(PaymentTypeEnum.WEIXIN.getStatus());
    paymentInfo.setOutTradeNo(orderInfo.getOutTradeNo());//資料庫欄位的長度改成32
    paymentInfo.setSubject(orderInfo.getTitle());
    paymentInfo.setTotalAmount(orderInfo.getAmount());
    paymentInfo.setPaymentStatus(PaymentStatusEnum.PAID.getStatus());
    paymentInfo.setTradeNo(transaction.getTransactionId());
    paymentInfo.setCallbackTime(new Date());
    paymentInfo.setCallbackContent(transaction.toString());
    baseMapper.insert(paymentInfo);
}

1.3、查單Controller

FrontWXPayController

@ApiOperation("查詢支付狀態")
@ApiImplicitParam(name = "outTradeNo",value = "訂單id", required = true)
@GetMapping("/queryPayStatus/{outTradeNo}")
public Result queryPayStatus(@PathVariable String outTradeNo) {
    //調用查詢介面
    boolean success = wxPayService.queryPayStatus(outTradeNo);
    if (success) {
        return Result.ok().message("支付成功");
    }
    return Result.ok().message("支付中").code(250);
}

1.4、查單Service

介面:WxPayService

/**
     * 查詢訂單支付狀態
     * @param outTradeNo
     * @return
     */
boolean queryPayStatus(String outTradeNo);

實現:WxPayServiceImpl

@Resource
private PaymentInfoService paymentInfoService;

@Override
public boolean queryPayStatus(String outTradeNo) {

    // 初始化服務
    NativePayService service = new NativePayService.Builder().config(rsaAutoCertificateConfig).build();

    // 調用介面
    try {

        QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
        // 調用request.setXxx(val)設置所需參數,具體參數可見Request定義
        request.setOutTradeNo(outTradeNo);
        request.setMchid(wxPayConfig.getMchId());

        // 調用介面
        Transaction transaction = service.queryOrderByOutTradeNo(request);
        Transaction.TradeStateEnum tradeState = transaction.getTradeState();

        //支付成功
        if(tradeState.equals(Transaction.TradeStateEnum.SUCCESS)){

            OrderInfo orderInfo = orderInfoService.selectByOutTradeNo(outTradeNo);

            //更新訂單狀態
            orderInfoService.updateStatus(outTradeNo, OrderStatusEnum.PAID.getStatus());
            //記錄支付日誌
            paymentInfoService.savePaymentInfo(orderInfo, transaction);

            //通知醫院修改訂單狀態
            //組裝參數
            HashMap<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("hoscode", orderInfo.getHoscode());
            paramsMap.put("hosOrderId", orderInfo.getHosOrderId());
            paramsMap.put("timestamp", HttpRequestHelper.getTimestamp());

            paramsMap.put("sign", HttpRequestHelper.getSign(paramsMap, "8af52af00baf6aec434109fc17164aae"));
            //發送請求
            JSONObject jsonResult = HttpRequestHelper.sendRequest(paramsMap, "http://localhost:9998/order/updatePayStatus");
            //解析響應
            if(jsonResult.getInteger("code") != 200) {
                log.error("查單失敗,"
                          + "code:" + jsonResult.getInteger("code")
                          + ",message:" + jsonResult.getString("message")
                         );
                throw new GuiguException(ResultCodeEnum.FAIL.getCode(), jsonResult.getString("message"));
            }

            //返回支付結果
            return true;//支付成功
        }

        return false;//支付中

    } catch (HttpException e) { // 發送HTTP請求失敗
        // 調用e.getHttpRequest()獲取請求列印日誌或上報監控,更多方法見HttpException定義
        log.error(e.getHttpRequest().toString());
        throw new GuiguException(ResultCodeEnum.FAIL);
    } catch (ServiceException e) { // 服務返回狀態小於200或大於等於300,例如500
        // 調用e.getResponseBody()獲取返回體列印日誌或上報監控,更多方法見ServiceException定義
        log.error(e.getResponseBody());
        throw new GuiguException(ResultCodeEnum.FAIL);
    } catch (MalformedMessageException e) { // 服務返回成功,返回體類型不合法,或者解析返回體失敗
        // 調用e.getMessage()獲取信息列印日誌或上報監控,更多方法見MalformedMessageException定義
        log.error(e.getMessage());
        throw new GuiguException(ResultCodeEnum.FAIL);
    }
}

2、前端整合

2.1、修改request.js

utils/request.js的響應攔截器中增加對250狀態的判斷

}else if (response.data.code !== 200) {
    
修改為

}else if (response.data.code !== 200 && response.data.code !== 250) {

2.2、api

在api/wxpay.js中添加的方法

//查詢訂單
queryPayStatus(outTradeNo) {
    return request({
        url: `/front/order/wxpay/queryPayStatus/${outTradeNo}`,
        method: 'get'
    })
},

3.3、show.vue輪詢查單

js中修改pay方法:每隔3秒查單

添加queryPayStatus方法

完善closeDialog方法:停止定時器

//發起支付
pay(){
  if(this.isPayShow) return
  this.isPayShow = true
  this.payText = '支付中.....'
    
  wxpayApi.nativePay(this.orderInfo.outTradeNo).then((response) => {
    this.codeUrl = response.data
    this.dialogPayVisible = true
      
    //每隔3秒查單
    this.timer = setInterval(()=>{
      console.log('輪詢查單:' + new Date())
      this.queryPayStatus()
    }, 3000)
  })
},
    
//查詢訂單狀態
queryPayStatus(){
  wxpayApi.queryPayStatus(this.orderInfo.outTradeNo).then(response => {
    if(response.code == 250){
        return
    }
    //清空定時器
    clearInterval(this.timer)
    window.location.reload()
  })
},

//關閉對話框
closeDialog(){
    //停止定時器
    clearInterval(this.timer)
    //恢復支付按鈕
    this.isPayShow = false
    this.payText = '支付'
}

3、查單應答超時

3.1、測試應答超時

//應答超時
//設置響應超時,支付成功後沒有及時響應,可能繼續輪詢查單,此時資料庫會記錄多餘的支付日誌
try {
    TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
    throw new RuntimeException(e);
}


//返回支付結果
return true;//支付成功

3.2、處理重覆通知

支付成功後,判斷訂單狀態:

OrderInfo orderInfo = orderInfoService.selectByOutTradeNo(outTradeNo);
//處理支付成功後重覆查單
//保證介面調用的冪等性:無論介面被調用多少次,產生的結果是一致的
Integer orderStatus = orderInfo.getOrderStatus();
if (OrderStatusEnum.UNPAID.getStatus().intValue() != orderStatus.intValue()) {
    return true;//支付成功、關單、。。。
}

//更新訂單狀態
//記錄支付日誌
......

本文來自博客園,作者:自律即自由-,轉載請註明原文鏈接:https://www.cnblogs.com/deyo/p/17495203.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.簡介 在做web ui自動化時,遇到操作視頻的時候有時比較讓人頭疼,定位時會發現只有一個<video>標簽,用selenium來實現的話比較麻煩,使用js後我們只需定位到video標簽,然後通過js 中處理video的相關屬性和方法就可實現,我們繼續往下看。 二.實例用法 1.獲取視頻的總時長( ...
  • >我們是[袋鼠雲數棧 UED 團隊](http://ued.dtstack.cn/),致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。。 >本文作者:琉易 [liuxianyu.cn](https://link.juejin.cn/?target=h ...
  • 其實並沒有所謂的 stencil Event,相反 stencil 鼓勵使用 `DOM event`。然而,Stencil 提供了一個 API 來指定組件可以觸發的事件,以及組件監聽的事件。 這是通過 Event()和 Listen()裝飾器實現的。 ## Event 裝飾器 組件可以使用事件發射器 ...
  • CSS3引入了很多新特性,比如: 1. 選擇器:CSS3引入了新的選擇器,如偽類選擇器、偽元素選擇器等,使得選擇元素更加靈活和精確。 2. 邊框圓角:CSS3允許通過 border-radius 屬性為元素的邊框添加圓角,創建圓形、橢圓形或具有不同角度的矩形邊框。 3. 盒陰影:使用 box-sha ...
  • 在JavaScript中,數組本質上是一種特殊的對象,它的類型值會返回 `object`。 如果我們需要比較兩個數組是否相等,不能像比較基本類型(String、Number、Boolean等)一樣,使用 ` ` (或 `==`) 來判斷,所以如果要比較數組是否相等,需要使用一些特殊方法。關於JS類型 ...
  • 一、約定大於配置 泰思勒定律也被稱為複雜度守恆定律。該定律指出每一個過程都有其固有的複雜性,存在一個臨界點,超過了這個點過程就不能再簡化了,你只能將固有的複雜性從一個地方移動到另外一個地方。 根據這個定律,在做系統設計時,預設會給用戶一個“套餐”,這個套餐會滿足多數人的需求。實在不滿足需求再特殊配置 ...
  • 代理模式是23種設計模式中結構型模式的一種,它的核心是通過代理類來完成其他對象的訪問,降低訪問者和被訪問者的耦合度,也對功能進行了增強。 ...
  • 在日常開發中會經常遇到一些需要非同步定時執行的業務訴求,典型的使用場景如:超時未支付訂單關單、每隔 2h 更新好友排行榜、3.22 日 17 點《xx》劇上線等。目前業務側多基於以下思路來快速搭建一個調度系統,mysql 或者 redis 隊列存儲待執行任務,通過 crontab 定時觸發應用完成“撈... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...