自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

別再亂搞 API 版本管理了!這些坑你踩過幾個(gè)?

開發(fā) 項(xiàng)目管理
在日常開發(fā)中,API版本的迭代幾乎是無法避免的事情。最近在項(xiàng)目中,我們遇到了需要在不影響舊客戶端的前提下,發(fā)布新版接口的需求。

在日常開發(fā)中,API版本的迭代幾乎是無法避免的事情。最近在項(xiàng)目中,我們遇到了需要在不影響舊客戶端的前提下,發(fā)布新版接口的需求。

一開始,我也用了最常見的做法:

GET /v1/products
GET /v2/products

乍一看很直觀,路徑一目了然,新老版本分開,大家都這么干,好像也沒毛病。

可惜,這種方式看似簡(jiǎn)單,實(shí)則問題重重。

路徑版本化的“表面光鮮”

我們可能會(huì)這么設(shè)計(jì)控制器:

@RestController
@RequestMapping("/v1/products")
public class ProductControllerV1 {
    // V1邏輯
}


@RestController
@RequestMapping("/v2/products")
public class ProductControllerV2 {
    // V2邏輯
}

這在項(xiàng)目初期確實(shí)很“快”。但是隨著版本增多,問題接踵而至:

  • 控制器、測(cè)試、文檔全要復(fù)制一份;
  • 每多一個(gè)版本,代碼重復(fù)度、維護(hù)成本、測(cè)試開銷都指數(shù)上升;
  • 文檔冗余、客戶端混亂、接口路徑不穩(wěn)定。

URL版本控制違背了 REST 的設(shè)計(jì)初衷

根據(jù) RESTful 的核心理念:

URI 是資源的永久地址,應(yīng)保持穩(wěn)定性。

路徑中包含版本號(hào),就像是給圖書的 ISBN 每年都改一次,不僅違背設(shè)計(jì)初衷,還容易造成客戶端的嚴(yán)重耦合。

舉個(gè)例子:

如果我們每年都改接口路徑:

/v1/products  
/v2/products  
/v3/products  
/legacy/products

老系統(tǒng)不能刪除,新系統(tǒng)又要兼容,最終的結(jié)果是:

  • 控制器臃腫不堪;
  • 老版本無法完全淘汰;
  • 文檔極度冗余;
  • 客戶端升級(jí)困難;
  • 出現(xiàn) 404 時(shí),用戶只能摸黑報(bào) bug。

更優(yōu)雅的做法:基于請(qǐng)求頭的版本控制

相比 URL 版本,通過 HTTP Header 來傳遞版本信息更貼合 REST 設(shè)計(jì)原則。

接口路徑不變:

GET /products

版本通過 Accept 頭協(xié)商:

  • 請(qǐng)求 V1:
Accept: application/vnd.icoderoad.v1+json
  • 請(qǐng)求 V2:
Accept: application/vnd.icoderoad.v2+json

Spring Boot 3.4 實(shí)現(xiàn)方式

項(xiàng)目結(jié)構(gòu)基于 com.icoderoad 包名:

package com.icoderoad.api.controller;


@RestController
@RequiredArgsConstructor
public class ProductController {


    private final VersionProvider versionProvider;
    private final IProductService productService;


    @GetMapping(value = "/products", produces = {
        "application/vnd.icoderoad.v1+json",
        "application/vnd.icoderoad.v2+json"
    })
    public ResponseEntity<List<IProductResponseDto>> getProducts(
            @RequestHeader(value = "Accept", defaultValue = "application/vnd.icoderoad.v1+json") String acceptHeader) {


        Version version = versionProvider.identifyVersion(acceptHeader);
        List<IProductResponseDto> products = productService.getProducts(version);
        return ResponseEntity.ok(products);
    }
}

VersionProvider 示例:

package com.icoderoad.api.version;


@Component
public class VersionProvider {


    public Version identifyVersion(String acceptHeader) {
        if (acceptHeader.contains("v2")) {
            return Version.V2;
        }
        return Version.V1;
    }
}

響應(yīng) DTO 接口:

public interface IProductResponseDto {
    String getName();
}

不同版本可以實(shí)現(xiàn)不同的 DTO,比如 ProductV1DtoProductV2Dto。

優(yōu)點(diǎn)解析

優(yōu)勢(shì)

說明

URI 穩(wěn)定

/products


永遠(yuǎn)不會(huì)改變


向后兼容

多版本共存,只需判斷 Header

更適配緩存

請(qǐng)求路徑不變,緩存更好命中

遵循 REST 規(guī)范

與 Fielding 的 REST 理論保持一致

擴(kuò)展建議:再往前走一步

增加 Swagger 兼容支持

使用 springdoc-openapi,通過 API Group 實(shí)現(xiàn)版本文檔拆分展示:

springdoc:
  group-configs:
    - group: v1
      paths-to-match: /products
      produces-to-match: application/vnd.icoderoad.v1+json
    - group: v2
      paths-to-match: /products
      produces-to-match: application/vnd.icoderoad.v2+json

自定義注解 + AOP 做更細(xì)粒度的控制

你也可以用注解標(biāo)識(shí)不同版本的方法,再配合 AOP 在運(yùn)行時(shí)動(dòng)態(tài)路由調(diào)用,非常優(yōu)雅。

那 URL 版本化有沒有場(chǎng)景?

有!但 僅限以下兩種情況

  1. 內(nèi)部系統(tǒng)或微服務(wù)之間通信,版本變動(dòng)可控
  2. 資源結(jié)構(gòu)發(fā)生破壞性變化,無法向后兼容(例如合規(guī)要求)

除此之外,請(qǐng)盡量使用 Header 版本控制。

總結(jié)

  • URI 是資源的“身份證”,不應(yīng)頻繁變化;
  • 版本控制建議通過 HTTP Header 實(shí)現(xiàn);
  • 教育前端和客戶端團(tuán)隊(duì)理解 Accept Header 的重要性;
  • 采用統(tǒng)一控制器,降低代碼重復(fù),維護(hù)成本更低。

如果你還在用 /v1/xxx 的方式管理版本,或許可以思考下?lián)Q個(gè)方式,擁抱更優(yōu)雅的 REST 實(shí)踐。

責(zé)任編輯:武曉燕 來源: 路條編程
相關(guān)推薦

2018-09-11 09:14:52

面試公司缺點(diǎn)

2024-04-01 08:05:27

Go開發(fā)Java

2023-03-13 13:36:00

Go擴(kuò)容切片

2025-04-29 10:17:42

2018-08-01 14:45:16

PHP編程語言

2018-01-10 06:17:24

2020-06-18 10:48:44

Linux 系統(tǒng) 數(shù)據(jù)

2018-07-30 16:18:51

容災(zāi)備份

2022-04-26 21:49:55

Spring事務(wù)數(shù)據(jù)庫

2017-07-17 15:46:20

Oracle并行機(jī)制

2019-12-12 14:32:26

SQL語句數(shù)據(jù)庫

2018-01-10 13:40:03

數(shù)據(jù)庫MySQL表設(shè)計(jì)

2025-02-10 00:27:54

2021-04-14 17:34:18

線程安全

2022-03-16 15:28:17

黑產(chǎn)安全網(wǎng)絡(luò)

2024-05-06 00:00:00

緩存高并發(fā)數(shù)據(jù)

2015-03-24 16:29:55

默認(rèn)線程池java

2020-11-03 13:50:31

Redis緩存數(shù)據(jù)庫

2019-09-25 15:30:15

2024-06-26 10:37:05

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)