常见的http状态码 + ResponseEntity

打印 上一主题 下一主题

主题 971|帖子 971|积分 2913

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
常见的http状态码

@ResponseStatus(HttpStatus.CREATED) 是 Spring Framework 中的注解,用于指定 HTTP 响应状态码。
1. 基本阐明



  • HttpStatus.CREATED 对应 HTTP 状态码 201
  • 表现哀求成功且创建了新的资源
  • 通常用于 POST 哀求的处置惩罚方法上
2. 利用场景和示例

基本利用

  1. @RestController
  2. @RequestMapping("/api/users")
  3. public class UserController {
  4.     @PostMapping
  5.     @ResponseStatus(HttpStatus.CREATED)  // 将返回 201 状态码
  6.     public User createUser(@RequestBody User user) {
  7.         return userService.createUser(user);
  8.     }
  9. }
复制代码
带有详细响应的利用

  1. @RestController
  2. @RequestMapping("/api/products")
  3. public class ProductController {
  4.     @PostMapping
  5.     @ResponseStatus(HttpStatus.CREATED)
  6.     public ResponseEntity<Product> createProduct(@RequestBody Product product) {
  7.         Product savedProduct = productService.save(product);
  8.         
  9.         // 创建资源的 URI
  10.         URI location = ServletUriComponentsBuilder
  11.             .fromCurrentRequest()
  12.             .path("/{id}")
  13.             .buildAndExpand(savedProduct.getId())
  14.             .toUri();
  15.         // 返回 201 状态码和资源位置
  16.         return ResponseEntity
  17.             .created(location)
  18.             .body(savedProduct);
  19.     }
  20. }
复制代码
3. 常用的 HTTP 状态码注解

  1. // 成功相关
  2. @ResponseStatus(HttpStatus.OK)           // 200 - 请求成功,返回资源或结果
  3. @ResponseStatus(HttpStatus.CREATED)      // 201 - 资源创建成功
  4. @ResponseStatus(HttpStatus.NO_CONTENT)   // 204 - 成功但无返回内容
  5. // 客户端错误
  6. @ResponseStatus(HttpStatus.BAD_REQUEST)         // 400 - 请求格式错误,客户端请求无效
  7. @ResponseStatus(HttpStatus.UNAUTHORIZED)        // 401 - 未授权,需身份验证
  8. @ResponseStatus(HttpStatus.FORBIDDEN)           // 403 - 禁止访问
  9. @ResponseStatus(HttpStatus.NOT_FOUND)          // 404 - 资源未找到
  10. @ResponseStatus(HttpStatus.CONFLICT)           // 409 - 资源冲突
  11. // 服务器错误
  12. @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 500 - 服务器内部错误
复制代码
假如需要更灵活地设置响应内容(如返回自定义的响应体或头部信息),可以利用 ResponseEntity,而不是 @ResponseStatus
@ResponseStatus 是一种简洁的方式,用于指定固定的 HTTP 状态码,但它的功能相对有限。假如需要更灵活地设置响应内容(如自定义响应体、响应头、动态状态码等),可以利用 ResponseEntity

1. 为什么选择 ResponseEntity?

ResponseEntity 是 Spring 提供的一个强大的工具,用于构建 HTTP 响应。它允许你:


  • 动态设置 HTTP 状态码
  • 自定义响应头
  • 返回复杂的响应体
  • 更灵活地处置惩罚不同的场景

2. ResponseEntity 的基本用法

示例 1: 返回自定义状态码和响应体

  1. @PostMapping("/users")
  2. public ResponseEntity<String> createUser(@RequestBody UserRequest userRequest) {
  3.     userService.createUser(userRequest);
  4.     return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully");
  5. }
复制代码


  • ResponseEntity.status(HttpStatus.CREATED):设置 HTTP 状态码为 201 Created。
  • .body("User created successfully"):设置响应体为自定义的字符串。

示例 2: 返回带有响应头的信息

  1. @PostMapping("/users")
  2. public ResponseEntity<String> createUser(@RequestBody UserRequest userRequest) {
  3.     userService.createUser(userRequest);
  4.     // 设置自定义响应头
  5.     HttpHeaders headers = new HttpHeaders();
  6.     headers.add("Custom-Header", "CustomHeaderValue");
  7.     return ResponseEntity.status(HttpStatus.CREATED)
  8.                          .headers(headers)
  9.                          .body("User created successfully");
  10. }
复制代码


  • HttpHeaders:用于设置响应头。
  • .headers(headers):将自定义的响应头添加到响应中。

示例 3: 返回带有资源位置的响应

在 RESTful API 中,创建资源后通常会返回 Location 头,指向新创建资源的 URI。
  1. @PostMapping("/users")
  2. public ResponseEntity<Void> createUser(@RequestBody UserRequest userRequest) {
  3.     Long userId = userService.createUser(userRequest);
  4.     // 构造资源的 URI
  5.     URI location = ServletUriComponentsBuilder
  6.         .fromCurrentRequest()
  7.         .path("/{id}")
  8.         .buildAndExpand(userId)
  9.         .toUri();
  10.     // 返回 201 Created 和 Location 头
  11.     return ResponseEntity.created(location).build();
  12. }
复制代码


  • ServletUriComponentsBuilder:用于动态构建资源的 URI。
  • .created(location):设置状态码为 201 Created,并添加 Location 头。

示例 4: 动态返回不同的状态码

  1. @PostMapping("/users")
  2. public ResponseEntity<String> createUser(@RequestBody UserRequest userRequest) {
  3.     if (userService.isDuplicate(userRequest)) {
  4.         return ResponseEntity.status(HttpStatus.CONFLICT).body("User already exists");
  5.     }
  6.     userService.createUser(userRequest);
  7.     return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully");
  8. }
复制代码


  • 假如用户已存在,返回 409 Conflict。
  • 假如创建成功,返回 201 Created。

3. 与 @ResponseStatus 的对比

特性@ResponseStatusResponseEntity设置状态码固定状态码,不能动态设置可以动态设置状态码自定义响应体不支持支持返回任意范例的响应体自定义响应头不支持支持通过 HttpHeaders 设置响应头实用场景简单场景,状态码固定复杂场景,需要动态响应代码简洁性更简洁代码稍显冗长
4. 综合示例:联合异常处置惩罚

自定义异常类

  1. @ResponseStatus(HttpStatus.NOT_FOUND) // 默认返回 404
  2. public class UserNotFoundException extends RuntimeException {
  3.     public UserNotFoundException(String message) {
  4.         super(message);
  5.     }
  6. }
复制代码
利用 ResponseEntity 处置惩罚异常

  1. @RestController
  2. @RequestMapping("/users")
  3. public class UserController {
  4.     @GetMapping("/{id}")
  5.     public ResponseEntity<User> getUser(@PathVariable Long id) {
  6.         User user = userService.findById(id)
  7.             .orElseThrow(() -> new UserNotFoundException("User not found with id: " + id));
  8.         return ResponseEntity.ok(user); // 返回 200 和用户信息
  9.     }
  10.     @ExceptionHandler(UserNotFoundException.class)
  11.     public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex) {
  12.         ErrorResponse errorResponse = new ErrorResponse("USER_NOT_FOUND", ex.getMessage());
  13.         return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
  14.     }
  15. }
复制代码


  • @ExceptionHandler:捕捉异常并返回自定义的响应。
  • ErrorResponse:自定义的错误响应体。

5. 总结



  • @ResponseStatus:得当简单场景,状态码固定,代码简洁。
  • ResponseEntity:得当复杂场景,允许动态设置状态码、响应头和响应体。
假如你的需求需要动态响应内容(如返回资源位置、错误信息、或自定义头部信息),ResponseEntity 是更灵活的选择。通过利用 ResponseEntity,我们可以更精确地控制 HTTP 响应的各个方面,使 API 更加灵活和专业。这对于构建复杂的 RESTful API 特别有用,由于它允许我们根据不同的业务场景返回不同的响应。
@RestController/@ResponseBody + ResponseEntity

利用 @RestController 或 @ResponseBody 返回对象时,Spring 会自动将返回的对象序列化为 JSON 并写入响应体,@RestController 或 @ResponseBody 返回的对象会自动设置状态码为 200 OK。 缺点:无法直接设置响应头或动态状态码。利用 @RestController 或 @ResponseBody 返回对象 假如需要返回特定的 HTTP 状态码,可以联合 ResponseEntity 利用。
利用 @RestController 或 @ResponseBody 直接返回对象时的重要缺点是无法直接设置响应头或动态状态码。以下是这些限制的详细阐明和办理方案:
1. 基本限制示例

  1. @RestController
  2. @RequestMapping("/api/users")
  3. public class UserController {
  4.    
  5.     // 直接返回对象的方式
  6.     @GetMapping("/{id}")
  7.     @ResponseBody
  8.     public User getUser(@PathVariable Long id) {
  9.         return userService.findById(id);  // 只能返回 200 OK
  10.     }
  11.    
  12.     // 无法直接设置响应头
  13.     @PostMapping
  14.     @ResponseBody
  15.     public User createUser(@RequestBody User user) {
  16.         return userService.save(user);  // 应该返回 201 Created,但只能是 200 OK
  17.     }
  18. }
复制代码
2. 重要限制


  • 状态码限制

    • 默认总是返回 200 OK
    • 无法动态设置状态码
    • 无法返回创建成功(201)等特定状态码

  • 响应头限制

    • 无法添加自定义响应头
    • 无法设置 Content-Disposition 等特别头部
    • 无法控制缓存相关头部

  • 错误处置惩罚限制

    • 无法直接返回错误状态码
    • 需要依赖全局异常处置惩罚

3. 办理方案

方案一:利用 ResponseEntity

  1. @RestController
  2. @RequestMapping("/api/users")
  3. public class UserController {
  4.     // 使用 ResponseEntity 返回特定状态码
  5.     @PostMapping
  6.     public ResponseEntity<User> createUser(@RequestBody User user) {
  7.         User savedUser = userService.save(user);
  8.         return ResponseEntity
  9.             .status(HttpStatus.CREATED)
  10.             .body(savedUser);
  11.     }
  12.     // 设置自定义响应头
  13.     @GetMapping("/{id}")
  14.     public ResponseEntity<User> getUser(@PathVariable Long id) {
  15.         return userService.findById(id)
  16.             .map(user -> ResponseEntity.ok()
  17.                 .header("X-Custom-Header", "value")
  18.                 .body(user))
  19.             .orElse(ResponseEntity.notFound().build());
  20.     }
  21. }
复制代码
方案二:利用 HttpServletResponse

  1. @RestController
  2. @RequestMapping("/api/users")
  3. public class UserController {
  4.     // 注入 HttpServletResponse
  5.     @PostMapping("/manual")
  6.     @ResponseBody
  7.     public User createUserManual(
  8.             @RequestBody User user,
  9.             HttpServletResponse response) {
  10.         User savedUser = userService.save(user);
  11.         response.setStatus(HttpServletResponse.SC_CREATED);
  12.         response.setHeader("X-Custom-Header", "value");
  13.         return savedUser;
  14.     }
  15. }
复制代码
方案三:利用统一响应包装类

  1. // 统一响应包装类
  2. public class ApiResponse<T> {
  3.     private int code;
  4.     private String message;
  5.     private T data;
  6.     private Map<String, String> headers = new HashMap<>();
  7.     // 构造方法和静态工厂方法
  8.     public static <T> ApiResponse<T> success(T data) {
  9.         return new ApiResponse<>(200, "Success", data);
  10.     }
  11.     public static <T> ApiResponse<T> created(T data) {
  12.         return new ApiResponse<>(201, "Created", data);
  13.     }
  14. }
  15. // 使用响应包装类的控制器
  16. @RestController
  17. @RequestMapping("/api/users")
  18. public class UserController {
  19.     @PostMapping
  20.     public ApiResponse<User> createUser(@RequestBody User user) {
  21.         User savedUser = userService.save(user);
  22.         return ApiResponse.created(savedUser);
  23.     }
  24. }
  25. // 响应拦截器
  26. @Component
  27. public class ApiResponseInterceptor implements ResponseBodyAdvice<ApiResponse<?>> {
  28.     @Override
  29.     public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
  30.         return ApiResponse.class.isAssignableFrom(returnType.getParameterType());
  31.     }
  32.     @Override
  33.     public ApiResponse<?> beforeBodyWrite(ApiResponse<?> body,
  34.             MethodParameter returnType,
  35.             MediaType selectedContentType,
  36.             Class<? extends HttpMessageConverter<?>> selectedConverterType,
  37.             ServerHttpRequest request,
  38.             ServerHttpResponse response) {
  39.         
  40.         if (body != null) {
  41.             response.setStatusCode(HttpStatus.valueOf(body.getCode()));
  42.             body.getHeaders().forEach((key, value) ->
  43.                 response.getHeaders().add(key, value));
  44.         }
  45.         return body;
  46.     }
  47. }
复制代码
方案四:利用 AOP 拦截

  1. @Aspect
  2. @Component
  3. public class ResponseHeaderAspect {
  4.     @Around("@annotation(responseHeaders)")
  5.     public Object addResponseHeaders(ProceedingJoinPoint joinPoint,
  6.             ResponseHeaders responseHeaders) throws Throwable {
  7.         Object result = joinPoint.proceed();
  8.         HttpServletResponse response =
  9.             ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
  10.                 .getResponse();
  11.         if (response != null) {
  12.             for (Header header : responseHeaders.value()) {
  13.                 response.setHeader(header.name(), header.value());
  14.             }
  15.         }
  16.         return result;
  17.     }
  18. }
  19. // 自定义注解
  20. @Target(ElementType.METHOD)
  21. @Retention(RetentionPolicy.RUNTIME)
  22. public @interface ResponseHeaders {
  23.     Header[] value();
  24. }
  25. @Target(ElementType.METHOD)
  26. @Retention(RetentionPolicy.RUNTIME)
  27. public @interface Header {
  28.     String name();
  29.     String value();
  30. }
  31. // 使用示例
  32. @RestController
  33. @RequestMapping("/api/users")
  34. public class UserController {
  35.     @PostMapping
  36.     @ResponseHeaders({
  37.         @Header(name = "X-Custom-Header", value = "value"),
  38.         @Header(name = "X-Created-By", value = "system")
  39.     })
  40.     public User createUser(@RequestBody User user) {
  41.         return userService.save(user);
  42.     }
  43. }
复制代码
方案五:利用过滤器

  1. @Component
  2. public class ResponseModifierFilter implements Filter {
  3.     @Override
  4.     public void doFilter(ServletRequest request,
  5.             ServletResponse response,
  6.             FilterChain chain) throws IOException, ServletException {
  7.         
  8.         HttpServletResponse httpResponse = (HttpServletResponse) response;
  9.         ContentCachingResponseWrapper responseWrapper =
  10.             new ContentCachingResponseWrapper(httpResponse);
  11.         chain.doFilter(request, responseWrapper);
  12.         // 修改响应
  13.         if (isUserCreationEndpoint(request)) {
  14.             responseWrapper.setStatus(HttpServletResponse.SC_CREATED);
  15.             responseWrapper.setHeader("X-Custom-Header", "value");
  16.         }
  17.         responseWrapper.copyBodyToResponse();
  18.     }
  19. }
复制代码
特性@RestController / @ResponseBodyResponseEntityHttpServletResponse默认状态码固定为 200 OK可动态设置可动态设置自定义响应头不支持支持支持动态状态码不支持支持支持代码复杂性简单中等较高推荐场景简单的 RESTful API需要动态状态码或自定义头部的场景特别场景(如文件流、低级操作) 详细解释如何利用 @RestController 或 @ResponseBody 联合 ResponseEntity 来返回对象和特定的 HTTP 状态码。
1. 基本用法

  1. @RestController
  2. @RequestMapping("/api/users")
  3. public class UserController {
  4.     @PostMapping
  5.     public ResponseEntity<User> createUser(@RequestBody User user) {
  6.         User savedUser = userService.save(user);
  7.         return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
  8.     }
  9.     @GetMapping("/{id}")
  10.     public ResponseEntity<User> getUser(@PathVariable Long id) {
  11.         return userService.findById(id)
  12.             .map(ResponseEntity::ok)  // 返回 200 OK
  13.             .orElse(ResponseEntity.notFound().build());  // 返回 404 Not Found
  14.     }
  15. }
复制代码
2. 统一响应格式

  1. // 统一响应格式
  2. public class ApiResponse<T> {
  3.     private int code;           // 状态码
  4.     private String message;     // 消息
  5.     private T data;            // 数据
  6.     private LocalDateTime timestamp = LocalDateTime.now();  // 时间戳
  7.     // 成功静态方法
  8.     public static <T> ApiResponse<T> success(T data) {
  9.         return new ApiResponse<>(200, "Success", data);
  10.     }
  11.     // 错误静态方法
  12.     public static <T> ApiResponse<T> error(int code, String message) {
  13.         return new ApiResponse<>(code, message, null);
  14.     }
  15.     // 构造方法、getter和setter
  16. }
复制代码
3. CRUD 操作示例

  1. @RestController
  2. @RequestMapping("/api/users")
  3. public class UserController {
  4.     private final UserService userService;
  5.     // 构造注入
  6.     public UserController(UserService userService) {
  7.         this.userService = userService;
  8.     }
  9.     // 创建用户
  10.     @PostMapping
  11.     public ResponseEntity<ApiResponse<User>> createUser(@RequestBody @Valid User user) {
  12.         User savedUser = userService.save(user);
  13.         return ResponseEntity
  14.             .status(HttpStatus.CREATED)
  15.             .body(ApiResponse.success(savedUser));
  16.     }
  17.     // 获取用户
  18.     @GetMapping("/{id}")
  19.     public ResponseEntity<ApiResponse<User>> getUser(@PathVariable Long id) {
  20.         return userService.findById(id)
  21.             .map(user -> ResponseEntity.ok(ApiResponse.success(user)))
  22.             .orElse(ResponseEntity
  23.                 .status(HttpStatus.NOT_FOUND)
  24.                 .body(ApiResponse.error(404, "User not found")));
  25.     }
  26.     // 更新用户
  27.     @PutMapping("/{id}")
  28.     public ResponseEntity<ApiResponse<User>> updateUser(
  29.             @PathVariable Long id,
  30.             @RequestBody @Valid User user) {
  31.         return userService.findById(id)
  32.             .map(existingUser -> {
  33.                 User updatedUser = userService.update(id, user);
  34.                 return ResponseEntity.ok(ApiResponse.success(updatedUser));
  35.             })
  36.             .orElse(ResponseEntity
  37.                 .status(HttpStatus.NOT_FOUND)
  38.                 .body(ApiResponse.error(404, "User not found")));
  39.     }
  40.     // 删除用户
  41.     @DeleteMapping("/{id}")
  42.     public ResponseEntity<ApiResponse<Void>> deleteUser(@PathVariable Long id) {
  43.         if (userService.existsById(id)) {
  44.             userService.deleteById(id);
  45.             return ResponseEntity.ok(ApiResponse.success(null));
  46.         }
  47.         return ResponseEntity
  48.             .status(HttpStatus.NOT_FOUND)
  49.             .body(ApiResponse.error(404, "User not found"));
  50.     }
  51.     // 获取用户列表(分页)
  52.     @GetMapping
  53.     public ResponseEntity<ApiResponse<Page<User>>> getUsers(
  54.             @RequestParam(defaultValue = "0") int page,
  55.             @RequestParam(defaultValue = "10") int size) {
  56.         Page<User> users = userService.findAll(PageRequest.of(page, size));
  57.         return ResponseEntity.ok(ApiResponse.success(users));
  58.     }
  59. }
复制代码
4. 异常处置惩罚

  1. @RestControllerAdvice
  2. public class GlobalExceptionHandler {
  3.     // 处理验证错误
  4.     @ExceptionHandler(MethodArgumentNotValidException.class)
  5.     public ResponseEntity<ApiResponse<Map<String, String>>> handleValidationErrors(
  6.             MethodArgumentNotValidException ex) {
  7.         Map<String, String> errors = new HashMap<>();
  8.         ex.getBindingResult().getFieldErrors().forEach(error ->
  9.             errors.put(error.getField(), error.getDefaultMessage())
  10.         );
  11.         
  12.         return ResponseEntity
  13.             .status(HttpStatus.BAD_REQUEST)
  14.             .body(ApiResponse.error(400, "Validation failed", errors));
  15.     }
  16.     // 处理业务逻辑异常
  17.     @ExceptionHandler(BusinessException.class)
  18.     public ResponseEntity<ApiResponse<Void>> handleBusinessException(BusinessException ex) {
  19.         return ResponseEntity
  20.             .status(ex.getStatus())
  21.             .body(ApiResponse.error(ex.getStatus().value(), ex.getMessage()));
  22.     }
  23.     // 处理其他未知异常
  24.     @ExceptionHandler(Exception.class)
  25.     public ResponseEntity<ApiResponse<Void>> handleUnknownException(Exception ex) {
  26.         return ResponseEntity
  27.             .status(HttpStatus.INTERNAL_SERVER_ERROR)
  28.             .body(ApiResponse.error(500, "Internal server error"));
  29.     }
  30. }
复制代码
5. 自定义业务异常

  1. public class BusinessException extends RuntimeException {
  2.     private final HttpStatus status;
  3.     public BusinessException(String message, HttpStatus status) {
  4.         super(message);
  5.         this.status = status;
  6.     }
  7.     public HttpStatus getStatus() {
  8.         return status;
  9.     }
  10. }
复制代码
6. 带条件的响应示例

  1. @RestController
  2. @RequestMapping("/api/orders")
  3. public class OrderController {
  4.     // 创建订单
  5.     @PostMapping
  6.     public ResponseEntity<ApiResponse<Order>> createOrder(@RequestBody @Valid OrderRequest request) {
  7.         // 检查库存
  8.         if (!inventoryService.checkStock(request)) {
  9.             return ResponseEntity
  10.                 .status(HttpStatus.CONFLICT)
  11.                 .body(ApiResponse.error(409, "Insufficient stock"));
  12.         }
  13.         // 检查用户信用
  14.         if (!userService.checkCredit(request.getUserId())) {
  15.             return ResponseEntity
  16.                 .status(HttpStatus.PAYMENT_REQUIRED)
  17.                 .body(ApiResponse.error(402, "Insufficient credit"));
  18.         }
  19.         // 创建订单
  20.         Order order = orderService.createOrder(request);
  21.         // 如果是加急订单,添加特殊响应头
  22.         if (request.isUrgent()) {
  23.             return ResponseEntity
  24.                 .status(HttpStatus.CREATED)
  25.                 .header("X-Priority", "High")
  26.                 .body(ApiResponse.success(order));
  27.         }
  28.         return ResponseEntity
  29.             .status(HttpStatus.CREATED)
  30.             .body(ApiResponse.success(order));
  31.     }
  32. }
复制代码
7. 文件上传响应示例

  1. @RestController
  2. @RequestMapping("/api/files")
  3. public class FileController {
  4.     @PostMapping("/upload")
  5.     public ResponseEntity<ApiResponse<FileInfo>> uploadFile(
  6.             @RequestParam("file") MultipartFile file) {
  7.         try {
  8.             FileInfo savedFile = fileService.store(file);
  9.             
  10.             return ResponseEntity
  11.                 .status(HttpStatus.CREATED)
  12.                 .header("Location", "/api/files/" + savedFile.getId())
  13.                 .body(ApiResponse.success(savedFile));
  14.         } catch (IOException e) {
  15.             return ResponseEntity
  16.                 .status(HttpStatus.INTERNAL_SERVER_ERROR)
  17.                 .body(ApiResponse.error(500, "Failed to upload file"));
  18.         }
  19.     }
  20.     @GetMapping("/download/{id}")
  21.     public ResponseEntity<Resource> downloadFile(@PathVariable String id) {
  22.         Resource file = fileService.loadAsResource(id);
  23.         
  24.         return ResponseEntity.ok()
  25.             .header(HttpHeaders.CONTENT_DISPOSITION,
  26.                 "attachment; filename="" + file.getFilename() + """)
  27.             .body(file);
  28.     }
  29. }
复制代码
8. 返回流式数据

假如需要返回流式数据(如文件下载),可以联合 ResponseEntity 和 InputStreamResource。
示例:返回文件下载

  1. @RestController  
  2. @RequestMapping("/files")  
  3. public class FileController {  
  4.     @GetMapping("/download/{filename}")  
  5.     public ResponseEntity<InputStreamResource> downloadFile(@PathVariable String filename) throws IOException {  
  6.         File file = fileService.getFile(filename);  
  7.         InputStreamResource resource = new InputStreamResource(new FileInputStream(file));  
  8.         return ResponseEntity.ok()  
  9.             .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName())  
  10.             .contentLength(file.length())  
  11.             .contentType(MediaType.APPLICATION_OCTET_STREAM)  
  12.             .body(resource);  
  13.     }  
  14. }  
复制代码


  • 响应:

    • 状态码:200 OK
    • 响应头:
      1. Content-Disposition: attachment; filename=myfile.txt  
      复制代码
    • 响应体:文件内容

9. 利用建议


  • 统一响应格式

    • 利用统一的响应封装类(如 ApiResponse)
    • 包含必要的状态码、消息和数据字段
    • 添加时间戳便于调试和日志追踪

  • 适当的状态码

    • 200: 成功获取资源
    • 201: 成功创建资源
    • 204: 成功处置惩罚但无返回内容
    • 400: 哀求参数错误
    • 401: 未认证
    • 403: 无权限
    • 404: 资源不存在
    • 409: 资源冲突
    • 500: 服务器错误

  • 异常处置惩罚

    • 利用全局异常处置惩罚器统一处置惩罚异常
    • 区分业务异常和体系异常
    • 提供清晰的错误信息

  • 响应头设置

    • 根据需要设置自定义响应头
    • 文件操作时设置适当的 Content-Type 和 Content-Disposition

  • 验证处置惩罚

    • 利用 @Valid 注解举行哀求验证
    • 提供详细的验证错误信息

通过这种方式,可以构建出统一、规范的 API 响应,便于客户端处置惩罚和调试。
10. 最佳实践建议



  • 优先利用 @RestController 或 @ResponseBody

    • 假如不需要动态设置状态码或响应头,直接返回对象即可,简单高效。

  • 利用 ResponseEntity 办理局限性

    • 当需要动态设置状态码或自定义响应头时,推荐利用 ResponseEntity,它是 Spring 提供的标准办理方案,代码优雅且易于维护。

  • 仅在特别场景下利用 HttpServletResponse

    • 假如需要直接操作底层响应流(如文件下载、流式数据),可以利用 HttpServletResponse。


  • 优先利用 ResponseEntity

    • 最清晰和直接的办理方案
    • 提供完备的响应控制
    • 范例安全且易于维护

  • 统一响应格式

    • 定义统一的响应包装类
    • 利用响应拦截器统一处置惩罚
    • 便于维护和扩展

  • 分层处置惩罚

    • 控制器层:业务逻辑和基本响应
    • 拦截器层:通用响应头和状态码
    • 过滤器层:全局响应修改

  • 异常处置惩罚
  1. @RestControllerAdvice
  2. public class GlobalExceptionHandler {
  3.     @ExceptionHandler(Exception.class)
  4.     public ResponseEntity<ApiResponse<String>> handleException(Exception ex) {
  5.         ApiResponse<String> response = ApiResponse.error(
  6.             500,
  7.             "Internal Server Error",
  8.             ex.getMessage()
  9.         );
  10.         
  11.         return ResponseEntity
  12.             .status(HttpStatus.INTERNAL_SERVER_ERROR)
  13.             .body(response);
  14.     }
  15. }
复制代码

  • 文档和注释
  1. /**
  2. * 用户控制器
  3. * 注意:直接返回对象时无法设置状态码和响应头
  4. * 建议使用 ResponseEntity 或其他替代方案
  5. */
  6. @RestController
  7. @RequestMapping("/api/users")
  8. public class UserController {
  9.     // 控制器方法...
  10. }
复制代码
通过以上方案,可以克服 @RestController 和 @ResponseBody 的限制,实现更灵活的响应控制。选择符合的方案取决于具体需求和项目架构。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

冬雨财经

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表