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

Spring Boot Rest API十大常見錯(cuò)誤及避免方法

開發(fā) 前端
本篇文章,我們將探討Spring Boot REST API中的十大常見錯(cuò)誤,解釋它們的影響,并使用最新的Spring Boot特性和最佳實(shí)踐提供更新的解決方案。

環(huán)境:SpringBoot3.2.5

1. 簡(jiǎn)介

構(gòu)建健壯且高效的REST API是現(xiàn)代應(yīng)用開發(fā)的關(guān)鍵。雖然Spring Boot簡(jiǎn)化了這一過程,但開發(fā)人員經(jīng)常會(huì)犯一些錯(cuò)誤,這些錯(cuò)誤可能導(dǎo)致效率低下、安全漏洞或用戶體驗(yàn)不佳。本篇文章,我們將探討Spring Boot REST API中的十大常見錯(cuò)誤,解釋它們的影響,并使用最新的Spring Boot特性和最佳實(shí)踐提供更新的解決方案。

圖片圖片

接下來,我們將詳細(xì)介紹上面10點(diǎn)常見錯(cuò)誤。

2. 錯(cuò)誤詳解

2.1 使用錯(cuò)誤的HTTP狀態(tài)碼

  • 錯(cuò)誤:對(duì)所有響應(yīng)(包括錯(cuò)誤響應(yīng))都返回200 OK狀態(tài)碼。
  • 影響:誤導(dǎo)性的狀態(tài)碼會(huì)使API客戶端感到困惑,并使調(diào)試變得困難。
  • 解決方案:根據(jù)具體情況始終使用適當(dāng)?shù)腍TTP狀態(tài)碼:

a.200 OK:請(qǐng)求成功。

b.201 Created:資源已成功創(chuàng)建。

c.400 Bad Request:輸入無效或存在驗(yàn)證錯(cuò)誤。

d.404 Not Found:資源不存在。

e.500 Internal Server Error:服務(wù)器內(nèi)部錯(cuò)誤(意外錯(cuò)誤)。 

@RestController
@RequestMapping("/api/products")
public class ProductController {


  @GetMapping("/{id}")
  public ResponseEntity<Product> getProductById(@PathVariable Long id) {
    return productService.findById(id)
      .map(product -> ResponseEntity.ok(product))
      .orElse(ResponseEntity.status(HttpStatus.NOT_FOUND).build()) ;
  }
}

為何重要:正確的HTTP狀態(tài)碼可以提高客戶端的理解能力和API的可靠性。

2.2 未驗(yàn)證輸入數(shù)據(jù)

  • 錯(cuò)誤:未經(jīng)驗(yàn)證就接受數(shù)據(jù)。
  • 影響:會(huì)導(dǎo)致安全漏洞和后續(xù)錯(cuò)誤。
  • 解決方案:在數(shù)據(jù)傳輸對(duì)象(DTO)上使用@Valid注解進(jìn)行輸入驗(yàn)證,并優(yōu)雅地處理錯(cuò)誤。
     
@RestController
@RequestMapping("/api/products")
public class ProductController {


  @PostMapping
  public ResponseEntity<String> createProduct(@Valid @RequestBody ProductDTO productDTO) {
    productService.save(productDTO) ;
    return ResponseEntity.status(HttpStatus.CREATED)
      .body("success");
  }
}


public record ProductDTO(
        @NotNull(message = "名稱不能為空") 
        String name,
        @Positive(message = "價(jià)格必須大于0") 
        Double price) {}

為何重要:驗(yàn)證輸入可以確保數(shù)據(jù)的完整性,并防止濫用。

2.3 忽略API版本控制

  • 錯(cuò)誤:開發(fā)API時(shí)不進(jìn)行版本控制會(huì)導(dǎo)致對(duì)客戶端的破壞性更改。
  • 影響:當(dāng)API發(fā)展時(shí),客戶端可能會(huì)遇到兼容性問題。
  • 解決方案:通過URI或自定義頭部實(shí)現(xiàn)API版本控制。
@RestController
@RequestMapping("/api/v1/products")
public class ProductV1Controller {
  @GetMapping("/{id}")
  public Product getProductV1(@PathVariable Long id) {
    return productService.findByIdV1(id);
  }
}


@RestController
@RequestMapping("/api/v2/products")
public class ProductV2Controller {
  @GetMapping("/{id}")
  public ProductDTO getProductV2(@PathVariable Long id) {
    return productService.findByIdV2(id);
  }
}

為何重要:版本控制可以在引入新功能的同時(shí)確保向后兼容性。

2.4 對(duì)端點(diǎn)和配置進(jìn)行硬編碼

  • 錯(cuò)誤:在代碼中硬編碼URL或服務(wù)端點(diǎn)。
  • 影響:使應(yīng)用程序難以維護(hù)和配置。
  • 解決方案:使用application.yml或application.properties將配置外部化。

配置文件

# application.yml
pack:
  product:
    service:
      url: https://api.pack.com/products

代碼注入

@Value("${pack.product.service.url}")
private String productServiceUrl;

為何重要:將配置外部化可以使您的應(yīng)用程序更加靈活且易于維護(hù)。

2.5 異常處理不當(dāng)

  • 錯(cuò)誤:允許異常未經(jīng)適當(dāng)格式化就傳播到客戶端。
  • 影響:客戶端會(huì)收到結(jié)構(gòu)不清晰的錯(cuò)誤信息,導(dǎo)致困惑。
  • 解決方案:使用帶有@ExceptionHandler的@ControllerAdvice進(jìn)行集中式的錯(cuò)誤處理。
@RestControllerAdvice
public class GlobalExceptionHandler {


  @ExceptionHandler(ResourceNotFoundException.class)
  public ResponseEntity<String> handleNotFound(ResourceNotFoundException ex) {
    return ResponseEntity.status(HttpStatus.NOT_FOUND)
      .body(ex.getMessage());
  }


  @ExceptionHandler(Exception.class)
  public ResponseEntity<String> handleGenericException(Exception ex) {
    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
      .body("發(fā)生錯(cuò)誤: " + ex.getMessage());
  }
}

為何重要:適當(dāng)?shù)漠惓L幚砟軌蛱嵘蛻趔w驗(yàn)和調(diào)試效率。

2.6 直接暴露JAP實(shí)體對(duì)象

  • 錯(cuò)誤:直接在API響應(yīng)中暴露數(shù)據(jù)庫實(shí)體。
  • 影響:導(dǎo)致數(shù)據(jù)庫與API之間緊密耦合。
  • 解決方案:使用DTO(數(shù)據(jù)傳輸對(duì)象)將API響應(yīng)與數(shù)據(jù)庫架構(gòu)解耦。
public record ProductDTO(Long id, String name, Double price) {}


public ProductDTO mapToDTO(Product product) {
  return new ProductDTO(product.getId(), product.getName(), product.getPrice());
}

為何重要:DTO(數(shù)據(jù)傳輸對(duì)象)提高了API的靈活性,并防止敏感數(shù)據(jù)泄露。

2.7 未實(shí)現(xiàn)分頁和過濾功能

  • 錯(cuò)誤:在單個(gè)響應(yīng)中返回大型數(shù)據(jù)集。
  • 影響:導(dǎo)致性能瓶頸和客戶端問題。
  • 解決方案:使用Pageable實(shí)現(xiàn)分頁和過濾功能。
@GetMapping
public Page<Product> getAllProducts(Pageable pageable) {
  return productRepository.findAll(pageable);
}

為何重要:分頁和過濾功能能夠提高API的性能和可擴(kuò)展性。

2.8 忽略接口安全

  • 錯(cuò)誤:未對(duì)REST API進(jìn)行保護(hù)或暴露敏感數(shù)據(jù)。
  • 影響:可能導(dǎo)致未經(jīng)授權(quán)的訪問和潛在的數(shù)據(jù)泄露。
  • 解決方案:使用帶有JWT或OAuth2的Spring Security。
@Bean
SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Throwable {
  http.csrf(csrf -> csrf.disable()) ;
  http.authorizeHttpRequests(registry -> {
    registry.requestMatchers("/*/*.js", "/*/*.css", "*.css", "*.js", "*.html", "/*/*.html", "/login", "/logout").permitAll() ;
    registry.requestMatchers("/**").authenticated() ;
  }) ;
  http.securityMatcher("/api/**", "/admin/**", "/login", "/logout", "/default-ui.css") ;
  http.addFilterBefore(authFilter(), UsernamePasswordAuthenticationFilter.class) ;
  return http.build() ;
}

以上指定了api接口及其它資源的訪問策略。

為何重要:安全性能夠保護(hù)敏感數(shù)據(jù)并確保合規(guī)性。

2.9 忽略API文檔

  • 錯(cuò)誤:跳過API文檔編寫。
  • 影響:導(dǎo)致其他開發(fā)人員難以使用你的API。
  • 解決方案:使用Knife4j進(jìn)行自動(dòng)生成的API文檔編寫。

引入依賴

<dependency>
  <groupId>com.github.xiaoymin</groupId>
  <artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>

配置

@Bean
public Docket createRestApi() {
  return new Docket(DocumentationType.OAS_30)
    // 是否啟用Swagger
    .enable(enabled)
    // 用來創(chuàng)建該API的基本信息,展示在文檔的頁面中(自定義展示的信息)
    .apiInfo(apiInfo())
    // 設(shè)置哪些接口暴露給Swagger展示
    .select()
    // 掃描所有有注解的api,用這種方式更靈活
    .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
    .paths(PathSelectors.any()).build()
    /* 設(shè)置安全模式,swagger可以設(shè)置訪問token */
    .securitySchemes(securitySchemes())
    .securityContexts(securityContexts());
}
private ApiInfo apiInfo() {
  // 用ApiInfoBuilder進(jìn)行定制
  return new ApiInfoBuilder()
    // 設(shè)置標(biāo)題
    .title("Pack_接口文檔")
    // 描述
    .description("Packxxx系統(tǒng),具體包括XXX,XXX模塊...")
    // 作者信息
    .contact(new Contact("xxxooo", null, null))
    // 版本
    .version("1.0.0").build();
}
private List<SecurityScheme> securitySchemes() {
  List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
  apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
  return apiKeyList;
}

為何重要:文檔能夠提高開發(fā)者的生產(chǎn)力和協(xié)作效率。

2.10 API中忽略HATEOAS

  • 錯(cuò)誤:返回不帶導(dǎo)航鏈接的純JSON數(shù)據(jù)。
  • 影響:客戶端缺乏執(zhí)行相關(guān)操作的指導(dǎo)。
  • 解決方案:使用Spring HATEOAS來包含導(dǎo)航鏈接。

引入依賴

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>

使用

import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;


@RestController
@RequestMapping("/products")
public class ProductController {


  @GetMapping("/{id}")
  public EntityModel<ProductDTO> queryProductById(@PathVariable Long id) {
    ProductDTO productDTO = new ProductDTO(id, "鼠標(biāo)", 66.6D) ;
    EntityModel<ProductDTO> productModel = EntityModel.of(
          productDTO,
          linkTo(methodOn(ProductController.class).queryProductById(productDTO.id())).withSelfRel(),
          linkTo(methodOn(ProductController.class).queryProducts()).withRel("all-products")
        ) ;
    return productModel ;
  }
  @GetMapping("")
  public List<EntityModel<ProductDTO>> queryProducts() {
    List<EntityModel<ProductDTO>> list = List.of(
          EntityModel.of(
                new ProductDTO(1L, "鼠標(biāo)", 66.6),
                linkTo(methodOn(ProductController.class).queryProductById(1L)).withSelfRel(),
                linkTo(methodOn(ProductController.class).queryProducts()).withRel("all-products")
              ),
          EntityModel.of(
                new ProductDTO(2L, "鍵盤", 88.8),
                linkTo(methodOn(ProductController.class).queryProductById(2L)).withSelfRel(),
                linkTo(methodOn(ProductController.class).queryProducts()).withRel("all-products")
              )
        ) ;
    return list ;
  }
}

訪問/products/666接口,輸出結(jié)果.

圖片圖片

圖片圖片

以上是我們手動(dòng)生成,如果你結(jié)合Spring REST Docs使用,那么你根本不需要自己寫這些。

責(zé)任編輯:武曉燕 來源: Spring全家桶實(shí)戰(zhàn)案例源碼
相關(guān)推薦

2009-10-22 09:52:37

2011-04-29 10:37:01

CRM

2025-03-26 02:00:00

API工具開發(fā)

2009-10-14 09:42:14

2013-09-13 14:43:16

2023-05-11 12:40:00

Spring控制器HTTP

2024-09-26 08:03:37

2022-10-17 07:35:52

Kubernetes工具日志

2013-07-03 09:42:32

網(wǎng)絡(luò)管理系統(tǒng)升級(jí)故障排查

2018-03-12 13:25:51

2010-08-16 13:51:22

DIV+CSS

2013-08-15 09:47:07

云遷移云技術(shù)

2024-03-04 13:23:00

數(shù)字化轉(zhuǎn)型

2022-01-10 06:43:27

ATT&CK網(wǎng)絡(luò)安全攻擊

2015-06-08 13:51:56

WiFi

2013-10-23 14:34:15

2020-04-29 14:37:24

JavaScript前端技術(shù)

2023-11-06 13:56:20

2019-07-29 15:15:45

2019-07-31 10:59:36

點(diǎn)贊
收藏

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