題培訓(xùn):從契約設(shè)計(jì)到聯(lián)調(diào)落地的工程實(shí)踐)
簡(jiǎn)介這份PPT課件面向工業(yè)自動(dòng)化領(lǐng)域的初學(xué)者與現(xiàn)場(chǎng)調(diào)試人員系統(tǒng)梳理工業(yè)控制設(shè)備中RS接口的硬件原理與通訊實(shí)踐。內(nèi)容從工業(yè)通訊接口概述切入覆蓋數(shù)控機(jī)床、PLC、變頻器等設(shè)備的通訊端口應(yīng)用并逐一介紹工業(yè)PC與個(gè)人PC上常見(jiàn)的VGA、PS2、MPI、串行/并行端口及RS485等接口類(lèi)型。針對(duì)個(gè)人計(jì)算機(jī)普遍缺失RS232、RS422/485端口的問(wèn)題課件給出轉(zhuǎn)換插卡、USB轉(zhuǎn)RS232電纜及RS232/RS422/RS485多級(jí)轉(zhuǎn)接等適配方案并深入講解RS232的通訊原理、單工/半雙工/全雙工方式、硬件握手信號(hào)線RxD、TxD、DTR、DSR、RTS、CTS與軟件握手字符控制同時(shí)強(qiáng)調(diào)跳線與自制措施在無(wú)標(biāo)準(zhǔn)端口時(shí)的應(yīng)用。資源包為1個(gè)pptx文件約5.73MB已有54人學(xué)習(xí)適合希望掌握工業(yè)通訊接口原理、快速排查基礎(chǔ)通訊故障的技術(shù)人員參考。1. 接口與通訊專(zhuān)題培訓(xùn)從一份 PPT 到能跑通的聯(lián)調(diào)現(xiàn)場(chǎng)手里拿到一份叫「接口與通訊專(zhuān)題培訓(xùn)(1).pptx」的材料多數(shù)人的第一反應(yīng)是翻一遍、存進(jìn)收藏夾、然后忘掉。但真正做過(guò)系統(tǒng)集成的人會(huì)盯著這個(gè)標(biāo)題多看兩眼——接口和通訊這兩件事恰恰是項(xiàng)目里最容易翻車(chē)、最難甩鍋、也最考驗(yàn)工程師功底的部分。接口講的是「數(shù)據(jù)長(zhǎng)什么樣、怎么約定」通訊講的是「數(shù)據(jù)怎么從 A 走到 B、走丟了怎么辦」。這兩件事合在一起就是一套系統(tǒng)能不能跟另一套系統(tǒng)說(shuō)上話的全部家當(dāng)。這份培訓(xùn)材料面向的不是剛學(xué)編程的新手而是已經(jīng)寫(xiě)過(guò)業(yè)務(wù)代碼、但一碰到跨系統(tǒng)聯(lián)調(diào)就頭大的工程師。它要解決的核心問(wèn)題很具體兩個(gè)系統(tǒng)對(duì)接時(shí)協(xié)議怎么選、報(bào)文怎么定、超時(shí)怎么設(shè)、斷了怎么補(bǔ)。接下來(lái)我不復(fù)述 PPT而是順著這個(gè)標(biāo)題把接口與通訊的落地路徑拆開(kāi)講清楚。2. 接口與通訊到底在解決什么問(wèn)題先分清協(xié)議層和數(shù)據(jù)層2.1 接口是契約通訊是運(yùn)輸別混為一談很多人把「接口」和「通訊」當(dāng)成一個(gè)詞用這是聯(lián)調(diào)階段吵架的根源。接口的本質(zhì)是一份契約字段叫什么、什么類(lèi)型、必填還是選填、取值范圍是多少、錯(cuò)誤碼怎么定義。通訊的本質(zhì)是一套運(yùn)輸規(guī)則用什么協(xié)議傳、連接怎么建立、超時(shí)多久、失敗重試幾次、消息順序要不要保證。契約沒(méi)定清楚雙方各寫(xiě)各的聯(lián)調(diào)時(shí)字段對(duì)不上運(yùn)輸規(guī)則沒(méi)定清楚契約再完美數(shù)據(jù)也可能在半路丟了或者重復(fù)了。舉個(gè)最常見(jiàn)的場(chǎng)景A 系統(tǒng)要調(diào) B 系統(tǒng)的下單接口。接口層面要約定的是請(qǐng)求體里orderId是字符串還是數(shù)字、amount保留幾位小數(shù)、返回的code為 0 是成功還是 200 是成功。通訊層面要約定的是走 HTTP 還是消息隊(duì)列、連接超時(shí)設(shè) 3 秒還是 10 秒、B 系統(tǒng)處理慢了 A 要不要重試、重試會(huì)不會(huì)導(dǎo)致重復(fù)下單。這兩層任何一層含糊上線后都是事故。所以看一份接口與通訊的培訓(xùn)材料第一件事是判斷它有沒(méi)有把這兩層分開(kāi)講。如果通篇只講「用 RESTful 風(fēng)格」那只是接口層的一半如果只講「用 Kafka 削峰」那只是通訊層的一半。真正能落地的方案一定是先定契約、再定運(yùn)輸、最后定異常處理。2.2 同步通訊和異步通訊的選型判斷同步通訊就是調(diào)用方發(fā)出請(qǐng)求后阻塞等待結(jié)果典型代表是 HTTP/RPC。異步通訊是調(diào)用方發(fā)出消息后不等結(jié)果由對(duì)方后續(xù)處理典型代表是消息隊(duì)列。選哪個(gè)不是技術(shù)偏好問(wèn)題而是業(yè)務(wù)語(yǔ)義問(wèn)題。判斷標(biāo)準(zhǔn)有三條。第一調(diào)用方是否必須立刻拿到結(jié)果才能繼續(xù)。比如用戶(hù)點(diǎn)擊支付必須立刻知道扣款成功還是失敗這是同步。第二被調(diào)用方的處理耗時(shí)是否穩(wěn)定且短。如果 B 系統(tǒng)處理一個(gè)請(qǐng)求要 30 秒同步調(diào)用會(huì)把 A 系統(tǒng)的線程池拖垮這時(shí)候要么改異步要么加緩沖。第三是否允許最終一致。訂單創(chuàng)建后通知積分系統(tǒng)加積分晚幾秒沒(méi)關(guān)系這就是異步的典型場(chǎng)景。我一般會(huì)用一個(gè)簡(jiǎn)單的表格來(lái)跟產(chǎn)品經(jīng)理對(duì)齊避免后期扯皮判斷維度選同步選異步調(diào)用方是否需要立即結(jié)果是否被調(diào)用方平均處理耗時(shí)小于 500ms大于 1s 或波動(dòng)大是否允許最終一致不允許允許失敗后是否需要人工介入需要可自動(dòng)補(bǔ)償流量峰值是否遠(yuǎn)超處理能力否是這張表不是絕對(duì)標(biāo)準(zhǔn)但能擋住八成「為什么不用消息隊(duì)列」或者「為什么要用消息隊(duì)列」的無(wú)效討論。2.3 一份可落地的接口契約該包含哪些字段契約不是寫(xiě)給人看的文檔而是能直接生成代碼和測(cè)試用例的規(guī)格。我習(xí)慣用 OpenAPI 或者 Protobuf 來(lái)描述但不管用什么格式下面這些信息一個(gè)都不能少。請(qǐng)求部分字段名、類(lèi)型、是否必填、長(zhǎng)度或精度限制、示例值、枚舉值列表。響應(yīng)部分成功時(shí)的數(shù)據(jù)結(jié)構(gòu)、失敗時(shí)的錯(cuò)誤碼和錯(cuò)誤信息結(jié)構(gòu)、分頁(yè)字段的命名和默認(rèn)值。通訊部分協(xié)議、方法、路徑、超時(shí)時(shí)間、重試策略、冪等鍵。這里有一個(gè)血淚經(jīng)驗(yàn)錯(cuò)誤碼一定要在契約階段就定死不要留到聯(lián)調(diào)時(shí)再補(bǔ)。我見(jiàn)過(guò)太多項(xiàng)目A 系統(tǒng)收到 B 系統(tǒng)返回的{error: 系統(tǒng)異常}然后 A 的工程師去問(wèn) B 的工程師「系統(tǒng)異常是什么異?!笲 的工程師說(shuō)「就是異常啊」。最后只能靠抓包和日志猜。正確的做法是錯(cuò)誤碼分段管理比如 1xxxx 表示參數(shù)錯(cuò)誤、2xxxx 表示業(yè)務(wù)規(guī)則拒絕、3xxxx 表示系統(tǒng)內(nèi)部錯(cuò)誤每個(gè)碼對(duì)應(yīng)一句明確的、可操作的提示。3. 把接口契約落成代碼從定義到可運(yùn)行的聯(lián)調(diào)環(huán)境3.1 用 OpenAPI 定義接口并生成服務(wù)端骨架假設(shè)我們要實(shí)現(xiàn)一個(gè)訂單查詢(xún)接口供外部系統(tǒng)調(diào)用。第一步不是寫(xiě)業(yè)務(wù)邏輯而是把契約寫(xiě)成 OpenAPI 描述文件。下面是一個(gè)最小可用的例子# order-api.yaml openapi: 3.0.3 info: title: 訂單查詢(xún)接口 version: 1.0.0 paths: /api/v1/orders/{orderId}: get: summary: 根據(jù)訂單號(hào)查詢(xún)訂單詳情 parameters: - name: orderId in: path required: true schema: type: string pattern: ^ORD[0-9]{12}$ # 訂單號(hào)格式ORD12位數(shù)字 responses: 200: description: 查詢(xún)成功 content: application/json: schema: $ref: #/components/schemas/Order 404: description: 訂單不存在 content: application/json: schema: $ref: #/components/schemas/Error components: schemas: Order: type: object required: [orderId, amount, status, createdAt] properties: orderId: type: string example: ORD202501011200 amount: type: number format: double example: 199.99 status: type: string enum: [CREATED, PAID, SHIPPED, COMPLETED, CANCELLED] createdAt: type: string format: date-time Error: type: object required: [code, message] properties: code: type: integer example: 40401 message: type: string example: 訂單不存在這份文件里pattern限定了訂單號(hào)格式enum限定了狀態(tài)取值范圍required標(biāo)明了必填字段。這些約束不是裝飾它們會(huì)直接生成校驗(yàn)代碼。用openapi-generator可以一鍵生成服務(wù)端骨架# 生成 Java Spring 服務(wù)端骨架 openapi-generator generate \ -i order-api.yaml \ -g spring \ -o ./order-service \ --additional-propertiesinterfaceOnlytrue,useTagstrue生成的代碼里每個(gè)字段的校驗(yàn)注解都已經(jīng)根據(jù)pattern和required自動(dòng)加好了。參數(shù)說(shuō)明-i指定契約文件-g指定生成語(yǔ)言或框架-o指定輸出目錄interfaceOnlytrue表示只生成接口定義不生成實(shí)現(xiàn)方便我們后續(xù)填充業(yè)務(wù)邏輯。這樣做的好處是契約改了重新生成一次校驗(yàn)邏輯自動(dòng)同步不會(huì)出現(xiàn)文檔和代碼兩張皮。3.2 通訊層的超時(shí)、重試和冪等怎么配接口定義好了接下來(lái)是通訊層。同步調(diào)用最常見(jiàn)的問(wèn)題是超時(shí)設(shè)置不合理。超時(shí)設(shè)太短對(duì)方稍微慢一點(diǎn)就報(bào)錯(cuò)設(shè)太長(zhǎng)調(diào)用方線程被占滿整個(gè)系統(tǒng)雪崩。我的經(jīng)驗(yàn)值是連接超時(shí) 1 到 3 秒讀取超時(shí)根據(jù)對(duì)方接口的 P99 耗時(shí)乘以 2 再加 1 秒。比如對(duì)方接口 P99 是 800ms讀取超時(shí)設(shè) 2.6 秒左右。重試不能無(wú)腦加。只有冪等的接口才能重試否則會(huì)造成重復(fù)下單、重復(fù)扣款。冪等鍵一般用業(yè)務(wù)唯一標(biāo)識(shí)比如訂單號(hào)。下面是一個(gè)帶超時(shí)和重試的 HTTP 調(diào)用示例import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # 配置重試策略只對(duì)冪等的 GET 請(qǐng)求重試最多 2 次退避因子 0.5 retry_strategy Retry( total2, backoff_factor0.5, status_forcelist[500, 502, 503, 504], allowed_methods[GET] # 只重試 GETPOST 不自動(dòng)重試 ) session requests.Session() adapter HTTPAdapter(max_retriesretry_strategy) session.mount(http://, adapter) session.mount(https://, adapter) try: # 連接超時(shí) 2 秒讀取超時(shí) 3 秒 resp session.get( http://order-service/api/v1/orders/ORD202501011200, timeout(2, 3) ) resp.raise_for_status() data resp.json() except requests.exceptions.Timeout: # 超時(shí)后的兜底邏輯記錄日志觸發(fā)告警不要直接拋給用戶(hù) print(調(diào)用訂單服務(wù)超時(shí)已記錄待補(bǔ)償) except requests.exceptions.HTTPError as e: print(fHTTP 錯(cuò)誤{e.response.status_code})這段代碼的關(guān)鍵點(diǎn)有三個(gè)。第一timeout(2, 3)是元組分別代表連接超時(shí)和讀取超時(shí)不要只寫(xiě)一個(gè)數(shù)字。第二allowed_methods[GET]限定了只有 GET 才自動(dòng)重試POST 請(qǐng)求如果失敗應(yīng)該由業(yè)務(wù)層根據(jù)冪等鍵決定是否重發(fā)。第三超時(shí)后的處理不是簡(jiǎn)單拋異常而是記錄日志并進(jìn)入補(bǔ)償流程。參數(shù)怎么改如果對(duì)方接口穩(wěn)定性差可以把total調(diào)到 3但backoff_factor要相應(yīng)調(diào)大避免重試風(fēng)暴。3.3 異步通訊的消息格式和消費(fèi)確認(rèn)異步通訊用消息隊(duì)列時(shí)消息格式的設(shè)計(jì)原則和接口契約一樣字段明確、版本可追溯、必填項(xiàng)清晰。我一般會(huì)在消息頭里放三個(gè)東西messageId全局唯一用于去重、timestamp消息產(chǎn)生時(shí)間用于判斷時(shí)效、version消息格式版本用于兼容升級(jí)。消費(fèi)確認(rèn)機(jī)制是異步通訊最容易踩坑的地方。以 RabbitMQ 為例如果消費(fèi)者收到消息后自動(dòng)確認(rèn)autoAck但處理過(guò)程中進(jìn)程崩潰消息就丟了。正確的做法是手動(dòng)確認(rèn)處理成功后再 ack處理失敗則 nack 并進(jìn)入死信隊(duì)列。import pika import json connection pika.BlockingConnection(pika.ConnectionParameters(localhost)) channel connection.channel() channel.queue_declare(queueorder_created, durableTrue) # 隊(duì)列持久化 def callback(ch, method, properties, body): try: msg json.loads(body) # 業(yè)務(wù)處理比如給用戶(hù)發(fā)短信 process_order(msg) # 處理成功手動(dòng)確認(rèn) ch.basic_ack(delivery_tagmethod.delivery_tag) except Exception as e: # 處理失敗拒絕消息并進(jìn)入死信隊(duì)列不重新入隊(duì)避免死循環(huán) ch.basic_nack(delivery_tagmethod.delivery_tag, requeueFalse) channel.basic_qos(prefetch_count1) # 每次只取一條處理完再取下一條 channel.basic_consume(queueorder_created, on_message_callbackcallback) channel.start_consuming()參數(shù)說(shuō)明durableTrue保證隊(duì)列在 RabbitMQ 重啟后不丟失prefetch_count1防止消費(fèi)者一次拿太多消息導(dǎo)致內(nèi)存溢出requeueFalse表示失敗消息不重新入隊(duì)而是進(jìn)死信隊(duì)列避免同一條消息反復(fù)失敗堵住隊(duì)列。這些配置看起來(lái)瑣碎但每一條都對(duì)應(yīng)著一種線上事故。4. 接口與通訊聯(lián)調(diào)排查那些文檔不會(huì)寫(xiě)的翻車(chē)現(xiàn)場(chǎng)4.1 現(xiàn)象接口返回 200 但業(yè)務(wù)說(shuō)沒(méi)收到數(shù)據(jù)原因通常有三種。第一種是通訊層成功但業(yè)務(wù)層失敗比如 HTTP 狀態(tài)碼 200但響應(yīng)體里code是 500調(diào)用方只判斷了 HTTP 狀態(tài)碼沒(méi)判斷業(yè)務(wù)碼。第二種是異步消息發(fā)送成功但消費(fèi)失敗生產(chǎn)者以為發(fā)出去了消費(fèi)者那邊因?yàn)榉葱蛄谢e(cuò)誤一直 nack。第三種是數(shù)據(jù)被中間件緩存了比如 CDN 或者網(wǎng)關(guān)緩存了 GET 請(qǐng)求的響應(yīng)導(dǎo)致后續(xù)請(qǐng)求拿到舊數(shù)據(jù)。解決方式調(diào)用方必須同時(shí)校驗(yàn) HTTP 狀態(tài)碼和業(yè)務(wù)錯(cuò)誤碼缺一不可。異步消息要在生產(chǎn)端和消費(fèi)端都打日志用messageId串聯(lián)。GET 請(qǐng)求如果返回的是實(shí)時(shí)數(shù)據(jù)要在響應(yīng)頭里加Cache-Control: no-cache。4.2 現(xiàn)象聯(lián)調(diào)時(shí)字段對(duì)不上A 說(shuō)發(fā)了 B 說(shuō)沒(méi)收到這是最經(jīng)典的接口契約問(wèn)題。A 系統(tǒng)發(fā)的字段叫order_idB 系統(tǒng)期望的是orderId或者 A 發(fā)的是字符串123B 期望的是數(shù)字123。更隱蔽的是時(shí)間格式A 發(fā)的是時(shí)間戳1735689600B 期望的是 ISO 格式2025-01-01T00:00:00Z。解決方式契約階段就用工具生成雙方代碼不要手寫(xiě)。如果已經(jīng)手寫(xiě)了聯(lián)調(diào)前先跑一遍契約測(cè)試用同一份 OpenAPI 文件生成請(qǐng)求和響應(yīng)校驗(yàn)器任何字段不匹配立刻報(bào)錯(cuò)。時(shí)間格式統(tǒng)一用 ISO 8601 帶時(shí)區(qū)不要用本地時(shí)間。4.3 現(xiàn)象重試導(dǎo)致重復(fù)下單A 系統(tǒng)調(diào)用 B 系統(tǒng)創(chuàng)建訂單B 處理成功但響應(yīng)超時(shí)A 觸發(fā)重試B 又創(chuàng)建了一筆訂單。這是重試機(jī)制沒(méi)有配合冪等設(shè)計(jì)的典型后果。解決方式B 系統(tǒng)必須支持冪等用 A 傳來(lái)的requestId或者業(yè)務(wù)唯一鍵做去重。具體做法是在 B 系統(tǒng)建一張冪等表收到請(qǐng)求先查requestId是否已處理已處理則直接返回上次的結(jié)果未處理則處理并記錄。A 系統(tǒng)在重試時(shí)必須攜帶同一個(gè)requestId不能每次重試生成新的。4.4 現(xiàn)象消息隊(duì)列積壓消費(fèi)速度跟不上原因可能是消費(fèi)者處理邏輯太重比如每條消息都去查數(shù)據(jù)庫(kù)、調(diào)外部接口。也可能是prefetch_count設(shè)得太大消費(fèi)者一次拿太多消息但處理不過(guò)來(lái)。還可能是消費(fèi)者數(shù)量不夠單線程消費(fèi)。解決方式先看監(jiān)控確認(rèn)是生產(chǎn)太快還是消費(fèi)太慢。如果是消費(fèi)太慢把消費(fèi)邏輯里的耗時(shí)操作異步化比如先落庫(kù)再異步處理。調(diào)整prefetch_count到合理值一般 10 到 50 之間。增加消費(fèi)者實(shí)例但要注意消息順序問(wèn)題如果業(yè)務(wù)要求順序消費(fèi)就不能簡(jiǎn)單加實(shí)例。4.5 現(xiàn)象跨系統(tǒng)調(diào)用偶發(fā)超時(shí)日志里看不出原因偶發(fā)超時(shí)最難查因?yàn)閺?fù)現(xiàn)不了。常見(jiàn)原因有DNS 解析慢、TCP 連接池不夠、對(duì)方服務(wù) GC 停頓、網(wǎng)絡(luò)抖動(dòng)。日志里只看到「timeout」沒(méi)有更細(xì)的信息。解決方式在調(diào)用鏈路里埋點(diǎn)記錄 DNS 解析耗時(shí)、連接建立耗時(shí)、首字節(jié)耗時(shí)、總耗時(shí)。用分布式追蹤工具把一次調(diào)用的完整鏈路串起來(lái)。如果發(fā)現(xiàn)是連接池不夠調(diào)大最大連接數(shù)如果是 DNS 問(wèn)題考慮本地緩存或者改用 IP 直連。這些手段不是為了炫技而是為了下次再出問(wèn)題時(shí)能五分鐘定位而不是五小時(shí)。5. 讓接口與通訊方案經(jīng)得起壓測(cè)和版本升級(jí)5.1 用契約測(cè)試鎖住兼容性接口一旦對(duì)外發(fā)布就不能隨便改字段。但業(yè)務(wù)在變接口遲早要升級(jí)。怎么保證升級(jí)不破壞老調(diào)用方答案是契約測(cè)試。具體做法是把每個(gè)版本的 OpenAPI 文件都存進(jìn)代碼倉(cāng)庫(kù)每次提交新版本時(shí)自動(dòng)跑一遍兼容性檢查確保沒(méi)有刪除字段、沒(méi)有修改字段類(lèi)型、沒(méi)有把必填改成選填反過(guò)來(lái)可以。# 用 openapi-diff 比較兩個(gè)版本的契約差異 openapi-diff old-api.yaml new-api.yaml --fail-on-incompatible--fail-on-incompatible表示只要有不兼容的變更就返回非零退出碼CI 流水線里直接卡住。這個(gè)習(xí)慣我堅(jiān)持了三年擋掉了至少五次可能引發(fā)線上故障的「小改動(dòng)」。5.2 壓測(cè)時(shí)重點(diǎn)看通訊層指標(biāo)不只看接口耗時(shí)很多人壓測(cè)只看接口的平均響應(yīng)時(shí)間這是不夠的。通訊層的指標(biāo)更能暴露問(wèn)題連接池等待時(shí)間、重試次數(shù)、超時(shí)次數(shù)、消息隊(duì)列積壓量。這些指標(biāo)在低并發(fā)時(shí)都是零一旦并發(fā)上來(lái)先崩的往往是通訊層。我一般會(huì)在壓測(cè)腳本里同時(shí)采集這些指標(biāo)用一張表對(duì)比不同并發(fā)下的表現(xiàn)并發(fā)數(shù)平均響應(yīng)時(shí)間P99 響應(yīng)時(shí)間連接池等待次數(shù)重試次數(shù)超時(shí)次數(shù)5045ms120ms00020080ms350ms1230500220ms1.8s15647810001.2s超時(shí)89221063這張表能直接告訴你系統(tǒng)的拐點(diǎn)在哪里。如果連接池等待次數(shù)在 200 并發(fā)時(shí)就開(kāi)始漲說(shuō)明連接池該調(diào)大了。如果重試次數(shù)在 500 并發(fā)時(shí)飆升說(shuō)明對(duì)方服務(wù)扛不住了要么限流要么降級(jí)。5.3 版本升級(jí)時(shí)的灰度策略接口升級(jí)不要一刀切。我的習(xí)慣是新版本接口先上線老版本繼續(xù)保留至少一個(gè)迭代周期。調(diào)用方按version字段或者 URL 路徑區(qū)分比如/api/v1/orders和/api/v2/orders并存?;叶绕陂g同時(shí)監(jiān)控兩個(gè)版本的錯(cuò)誤率和耗時(shí)確認(rèn)新版本穩(wěn)定后再通知調(diào)用方遷移最后下線老版本。這里有一個(gè)后悔藥式的教訓(xùn)曾經(jīng)有一次升級(jí)我覺(jué)得改動(dòng)很小直接把老版本下線了結(jié)果有一個(gè)調(diào)用方?jīng)]收到通知第二天業(yè)務(wù)反饋功能不可用。從那以后我堅(jiān)持「老版本至少多活一個(gè)月」并且在網(wǎng)關(guān)層記錄每個(gè)版本的調(diào)用量調(diào)用量降到零之后再下線。接口與通訊這件事說(shuō)到底就是「把約定寫(xiě)死、把異常想全、把退路留好」。我現(xiàn)在的習(xí)慣是每定義一個(gè)接口先問(wèn)三個(gè)問(wèn)題對(duì)方超時(shí)了我怎么辦、對(duì)方重試了我怎么辦、對(duì)方升級(jí)了我怎么辦。這三個(gè)問(wèn)題答不上來(lái)接口就不算定義完。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取