fix: 用StreamingResponseBody手动控制Content-Type,彻底解决charset注入问题
This commit is contained in:
parent
d7d585ed42
commit
fd6bf7c071
@ -3,18 +3,13 @@ package com.petstore.controller;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDate;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
@ -66,42 +61,55 @@ public class FileController {
|
||||
}
|
||||
|
||||
@GetMapping("/image/**")
|
||||
public ResponseEntity<Resource> getImage(HttpServletRequest request) throws IOException {
|
||||
public void getImage(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String path = request.getRequestURI().replace("/api/upload/image", "");
|
||||
String basePath = uploadPath.endsWith("/") ? uploadPath : uploadPath + "/";
|
||||
File file = new File(basePath + path);
|
||||
if (!file.exists()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
String contentType = Files.probeContentType(file.toPath());
|
||||
if (contentType == null) contentType = "image/jpeg";
|
||||
// 去掉可能的 charset 参数,避免 video Content-Type 被设为 "video/mp4;charset=UTF-8"
|
||||
// 去掉可能的 charset 参数
|
||||
int semi = contentType.indexOf(';');
|
||||
if (semi >= 0) contentType = contentType.substring(0, semi).trim();
|
||||
// 直接用 header 设置 Content-Type,绕过 Spring 的 Accept-Charset 逻辑
|
||||
return ResponseEntity.ok()
|
||||
.header("Content-Type", contentType)
|
||||
.body(new FileSystemResource(file));
|
||||
// 手动设置响应头,彻底掌控 Content-Type(绕过 Spring ResourceHttpMessageConverter)
|
||||
response.setContentType(contentType);
|
||||
response.setContentLengthLong(file.length());
|
||||
response.setHeader("Accept-Ranges", "bytes");
|
||||
// 支持范围请求(HTTP 206),video 播放器需要
|
||||
response.setHeader("Content-Disposition", "inline");
|
||||
try (var in = Files.newInputStream(file.toPath());
|
||||
var out = response.getOutputStream()) {
|
||||
in.transferTo(out);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// 兼容旧路径:/2026/04/01/xxx.jpg
|
||||
@GetMapping("/legacy/**")
|
||||
public ResponseEntity<Resource> getLegacyImage(HttpServletRequest request) throws IOException {
|
||||
public void getLegacyImage(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String path = request.getRequestURI().replace("/api/upload/legacy", "");
|
||||
String basePath = uploadPath.endsWith("/") ? uploadPath : uploadPath + "/";
|
||||
File file = new File(basePath + path);
|
||||
if (!file.exists()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
String contentType = Files.probeContentType(file.toPath());
|
||||
if (contentType == null) contentType = "image/jpeg";
|
||||
// 去掉可能的 charset 参数,避免 video Content-Type 被设为 "video/mp4;charset=UTF-8"
|
||||
int semi = contentType.indexOf(';');
|
||||
if (semi >= 0) contentType = contentType.substring(0, semi).trim();
|
||||
// 直接用 header 设置 Content-Type,绕过 Spring 的 Accept-Charset 逻辑
|
||||
return ResponseEntity.ok()
|
||||
.header("Content-Type", contentType)
|
||||
.body(new FileSystemResource(file));
|
||||
response.setContentType(contentType);
|
||||
response.setContentLengthLong(file.length());
|
||||
response.setHeader("Accept-Ranges", "bytes");
|
||||
response.setHeader("Content-Disposition", "inline");
|
||||
try (var in = Files.newInputStream(file.toPath());
|
||||
var out = response.getOutputStream()) {
|
||||
in.transferTo(out);
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/** produces 显式 UTF-8,避免网关/客户端按 ISO-8859-1 解码导致 message 中文乱码 */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user