我之前使用的是以下版本的 Spring Spring Boot:
<springVersion>5.0.16.RELEASE</springVersion>
<springBootVersion>2.0.5.RELEASE</springBootVersion>
以及以下處理多部分/混合上傳的類。使用上面的 Spring 版本一切正常:
暫存API.java
import io.swagger.annotations.*;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.Valid;
import javax.validation.constraints.*;
@javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2022-05-10T11:14:13.587 01:00[Europe/London]")
@Api(value = "Staging", description = "API")
public interface StagingApi {
@ApiOperation(value = "", nickname = "createOrReplaceBatch", notes = "", tags={ })
@ApiResponses(value = {
@ApiResponse(code = 200, message = ""),
@ApiResponse(code = 400, message = ""),
@ApiResponse(code = 500, message = "") })
@RequestMapping(value = "/batches/{batchId}",
consumes = { "multipart/mixed" },
method = RequestMethod.PUT)
ResponseEntity<Void> createOrReplaceBatch(
@ApiParam(value = "" ,required=true) @RequestHeader(value="X-TENANT-ID", required=true) String X_TENANT_ID,
@Size(min=1) @ApiParam(value = "",required=true) @PathVariable("batchId") String batchId,
@ApiParam(value = "" ) @Valid @RequestBody Object body);
}
暫存控制器.java
public ResponseEntity<Void> createOrReplaceBatch(
@ApiParam(value = "Identifies the tenant making the request.", required = true)
@RequestHeader(value = "X-TENANT-ID", required = true) String X_TENANT_ID,
@Size(min = 1) @ApiParam(value = "Identifies the batch.", required = true)
@PathVariable("batchId") String batchId,
Object body)
{
final ServletFileUpload fileUpload = new ServletFileUpload();
final FileItemIterator fileItemIterator;
try {
fileItemIterator = fileUpload.getItemIterator(request);
} catch (final FileUploadException | IOException ex) {
LOGGER.error("Error getting FileItemIterator", ex);
throw new WebMvcHandledRuntimeException(HttpStatus.BAD_REQUEST, ex.getMessage());
}
try {
batchDao.saveFiles(new TenantId(X_TENANT_ID), new BatchId(batchId), fileItemIterator);
return new ResponseEntity<>(HttpStatus.OK);
} catch (final InvalidTenantIdException | InvalidBatchIdException | IncompleteBatchException | InvalidBatchException ex) {
throw new WebMvcHandledRuntimeException(HttpStatus.BAD_REQUEST, ex.getMessage());
} catch (final StagingException ex) {
throw new WebMvcHandledRuntimeException(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage());
}
}
成功處理請求的日志:
[2022-05-10 11:12:14.861Z #bc7.042 DEBUG - - ] o.s.w.s.m.m.a.RequestMappingHandlerMapping: Looking up handler method for path /batches/test-batch
[2022-05-10 11:12:14.861Z #bc7.042 DEBUG - - ] o.s.w.a.FixedContentNegotiationStrategy: Requested media types: [application/json, */*]
[2022-05-10 11:12:14.861Z #bc7.042 DEBUG - - ] o.s.w.a.FixedContentNegotiationStrategy: Requested media types: [application/json, */*]
[2022-05-10 11:12:14.862Z #bc7.042 DEBUG - - ] o.s.w.a.FixedContentNegotiationStrategy: Requested media types: [application/json, */*]
[2022-05-10 11:12:14.863Z #bc7.042 DEBUG - - ] o.s.w.s.m.m.a.RequestMappingHandlerMapping: Returning handler method [public org.springframework.http.ResponseEntity<java.lang.Void> com.acme.corp.staging.StagingController.createOrReplaceBatch(java.lang.String,java.lang.String,java.lang.Object)]
[2022-05-10 11:12:14.863Z #bc7.042 DEBUG - - ] o.s.b.f.s.DefaultListableBeanFactory: Returning cached instance of singleton bean 'stagingController'
[2022-05-10 11:12:14.866Z #bc7.042 DEBUG - - ] o.s.b.w.s.f.OrderedRequestContextFilter: Bound request context to thread: org.apache.catalina.connector.RequestFacade@37f2254a
[2022-05-10 11:12:14.870Z #bc7.042 DEBUG - - ] o.s.w.s.DispatcherServlet: DispatcherServlet with name 'dispatcherServlet' processing PUT request for [/batches/test-batch]
[2022-05-10 11:12:14.871Z #bc7.042 DEBUG - - ] o.s.w.s.m.m.a.RequestMappingHandlerMapping: Looking up handler method for path /batches/test-batch
[2022-05-10 11:12:14.871Z #bc7.042 DEBUG - - ] o.s.w.a.FixedContentNegotiationStrategy: Requested media types: [application/json, */*]
[2022-05-10 11:12:14.871Z #bc7.042 DEBUG - - ] o.s.w.a.FixedContentNegotiationStrategy: Requested media types: [application/json, */*]
[2022-05-10 11:12:14.871Z #bc7.042 DEBUG - - ] o.s.w.a.FixedContentNegotiationStrategy: Requested media types: [application/json, */*]
[2022-05-10 11:12:14.871Z #bc7.042 DEBUG - - ] o.s.w.s.m.m.a.RequestMappingHandlerMapping: Returning handler method [public org.springframework.http.ResponseEntity<java.lang.Void> com.acme.corp.staging.StagingController.createOrReplaceBatch(java.lang.String,java.lang.String,java.lang.Object)]
[2022-05-10 11:12:14.871Z #bc7.042 DEBUG - - ] o.s.b.f.s.DefaultListableBeanFactory: Returning cached instance of singleton bean 'stagingController'
[2022-05-10 11:12:14.932Z #bc7.042 DEBUG - 10c9] o.s.w.a.FixedContentNegotiationStrategy: Requested media types: [application/json, */*]
[2022-05-10 11:12:14.933Z #bc7.042 DEBUG - - ] o.s.w.s.DispatcherServlet: Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
[2022-05-10 11:12:14.933Z #bc7.042 DEBUG - - ] o.s.w.s.DispatcherServlet: Successfully completed request
但是,當我嘗試將 Spring 和 Spring Boot 的版本更新為:
<springVersion>5.2.4.RELEASE</springVersion>
<springBootVersion>2.2.6.RELEASE</springBootVersion>
相同的請求失敗并回傳 415 UNSUPPORTED_MEDIA_TYPE 回應。
失敗請求的日志:
[2022-05-10 11:31:52.158Z #dc2.024 INFO - - ] o.a.c.c.C..localhost.: Initializing Spring DispatcherServlet 'dispatcherServlet'
[2022-05-10 11:31:52.158Z #dc2.024 INFO - - ] o.s.w.s.DispatcherServlet: Initializing Servlet 'dispatcherServlet'
[2022-05-10 11:31:52.158Z #dc2.024 DEBUG - - ] o.s.w.s.DispatcherServlet: Detected StandardServletMultipartResolver
[2022-05-10 11:31:52.162Z #dc2.024 DEBUG - - ] o.s.w.s.DispatcherServlet: enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
[2022-05-10 11:31:52.162Z #dc2.024 INFO - - ] o.s.w.s.DispatcherServlet: Completed initialization in 4 ms
[2022-05-10 11:31:52.165Z #dc2.024 DEBUG - - ] o.s.w.s.DispatcherServlet: PUT "/batches/test-batch", parameters={}
[2022-05-10 11:31:52.192Z #dc2.024 DEBUG - - ] o.s.w.s.m.m.a.RequestMappingHandlerMapping: Mapped to com.acme.corp.staging.StagingController#createOrReplaceBatch(String, String, Object)
[2022-05-10 11:31:52.202Z #dc2.024 DEBUG - a17e] o.s.w.s.m.m.a.ServletInvocableHandlerMethod: Could not resolve parameter [2] in public org.springframework.http.ResponseEntity<java.lang.Void> com.acme.corp.staging.StagingController.createOrReplaceBatch(java.lang.String,java.lang.String,java.lang.Object): Content type 'multipart/mixed;boundary=efb8369b-607b-4dcf-9f92-e6cd8244db1e;charset=UTF-8' not supported
[2022-05-10 11:31:52.204Z #dc2.024 DEBUG - a17e] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver: Using @ExceptionHandler acme.corp.staging.exceptions.WebMvcExceptionHandler#handleException(Exception, WebRequest)
[2022-05-10 11:31:52.206Z #dc2.024 DEBUG - a17e] o.s.w.s.m.m.a.HttpEntityMethodProcessor: No match for [application/json, */*], supported: []
[2022-05-10 11:31:52.206Z #dc2.024 DEBUG - a17e] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver: Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/mixed;boundary=efb8369b-607b-4dcf-9f92-e6cd8244db1e;charset=UTF-8' not supported]
[2022-05-10 11:31:52.206Z #dc2.024 DEBUG - a17e] o.s.w.s.DispatcherServlet: Completed 415 UNSUPPORTED_MEDIA_TYPE
除錯這個,這是我發現的:
當我使用最新的 Spring 版本向上述端點發送 PUT 請求時,將呼叫
這是 的值contentType:

false因此,發生的情況是,當被詢問時,這些轉換器中的每一個都回傳:
canRead(targetClass=java.lang.Object, contentType=multipart/mixed; boundary=efb8369b-607b-4dcf-9f92-e6cd8244db1e;charset=UTF-8
這導致body沒有被分配一個值,并拋出一個HttpMediaTypeNotSupportedException:
if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
(noContentType && !message.hasBody())) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType,
getSupportedMediaTypes(targetClass != null ? targetClass : Object.class));
}
我嘗試使用我原始帖子中列出的舊 Spring 版本逐步執行相同的代碼(例如,為了查看早期 Spring 版本是否有更多訊息轉換器):
<springVersion>5.0.16.RELEASE</springVersion>
<springBootVersion>2.0.5.RELEASE</springBootVersion>
但我發現,回圈通過訊息轉換器的這段代碼不是使用這些較舊的 Spring 版本執行的
我不確定現在正在執行此代碼(并引發例外)的這些 Spring 版本之間發生了什么變化,以前沒有?
uj5u.com熱心網友回復:
請參閱@wilkinsona在打開的春季啟動問題中的回答:
Spring Framework 5.1 還支持多部分 PUT 請求。這意味著 Spring MVC 現在正在讀取正文,使其無法用于公共上傳。
您應該切換到使用 MVC 的內置多部分支持。有幾種不同的方法可以做到這一點,例如:
@RestController public class StagingController implements StagingApi { public ResponseEntity<Void> createOrReplaceBatch(@PathVariable("batchId") String batchId, MultipartHttpServletRequest request) { try { Collection<Part> parts = request.getParts();
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/476774.html
