У меня есть простой сервис для загрузки файлов. Образец кода
@RestController
@RequestMapping("/file")
public class FileController {
@PostMapping("/upload")
public ResponseEntity<?> uploadFile(@RequestParam("file") MultipartFile file,
@RequestParam(value = "delay", required = false, defaultValue = "0") int delay) throws Exception {
System.out.println(String.join(System.getProperty("line.separator"),
"File Name => " + file.getOriginalFilename(),
"File Size => " + file.getSize() + "bytes",
"File Content Type => " + file.getContentType()));
TimeUnit.MILLISECONDS.sleep(delay);
return ResponseEntity.ok(file.getName() + " uploaded");
}
}
и CustomExceptionHandler
, который возвращает BAD_REQUEST
, если есть MultipartException
:
@Configuration
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(MultipartException.class)
public ResponseEntity<String> handleMultipartException(MultipartException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());
}
}
Максимальный размер файла application.yml составляет 10 МБ:
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
Если я загружаю большой файл, это дает мне статус 400
, как ожидалось
Когда я пытаюсь сделать то же самое через весенний облачный шлюз, я получаю следующий результат:
и журналы показывают следующее:
2019-11-08 00:36:10.797 ERROR 21904 --- [ctor-http-nio-2] a.w.r.e.AbstractErrorWebExceptionHandler : [86e57f7e] 500 Server Error for HTTP POST "/product-service/file/upload"
reactor.netty.http.client.PrematureCloseException: Connection has been closed BEFORE response, while sending request body
Обратите внимание, что шлюз настроен на прием файлов большого размера с RequestSize
фильтром, установленным глобально, чтобы занимать больше 10 МБ.
Как я могу получить тот же код ответа, что и нижестоящая служба?
Кроме того, я проверяю с помощью традиционного зуула и тоже получаю 500
ошибку.
Для шлюза, я знаю, что в этом конкретном случае мы можем использовать фильтр RequestSize
, и теперь шлюз вернет код ошибки, но тогда мы должны заранее идентифицировать все маршруты, которые ожидают этого. Кроме того, другая проверка в API, например авторизация и т. д., будет иметь ту же проблему. Код ответа, полученный в результате этих проверок, не будет распространяться.
Пример кода spring-cloud-gateway / product-service / eureka - https://github.com/dhananjay12/spring-cloud/tree/master/spring-routing