J'ai un serveur API qui a été construit avec Spring Boot 2.1 sur le domaine public qui sert également les API et le téléchargement de fichiers.
Ces derniers jours, nous souhaitons mettre à niveau ce serveur Spring Boot pour utiliser SSL (https). Avant de configurer les paramètres SSL dans Spring Boot. L'API pour le téléchargement de fichiers fonctionne très bien (100% de téléchargement réussi).
Après avoir configuré les paramètres SSL dans Spring Boot. L'API pour le téléchargement de fichiers fonctionne mais seulement 50% du téléchargement réussi, les autres 50% ont reçu une mauvaise requête http 400. (Nous sommes sûrs que le problème n'est pas lié au Web frontal, car nous utilisons le Swagger qui fourni avec Spring Boot pour tester peut obtenir le même résultat)
Et nous recherchons les journaux du serveur de Spring Boot. Lorsque la mauvaise requête http 400 se produit, il n'y avait aucun journal concernant la mauvaise requête http 400. Nous étudions plusieurs jours et sondons sur Internet mais ne pouvons toujours pas résoudre ce problème. Veuillez donner de l'aide.
Nous essayons déjà de désactiver csrf (soit dans le fichier de propriétés ou via la classe de configuration) et de nombreuses autres solutions fournies sur Internet mais qui ne fonctionnent toujours pas.
Environnement: Spring Boot 2.1.13 (qui est la dernière version de Spring Boot 2.1)
Paramètres dans le fichier de propriétés: (seulement la section de configuration SSL ajoutée dans le fichier de propriétés, et le SSL (https) est activé avec succès)
HttpEntityMethodProcessor : No match for [application/json;charset=UTF-8], supported: [] ExceptionHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present] DispatcherServlet : Completed 400 BAD_REQUEST
Mon contrôleur pour le téléchargement de fichiers:
Request URL: https://example.com:8443/v1/fileupload/dataimport Request Method: POST Status Code: 400 Remote Address: 111.222.111.222:8443 Referrer Policy: no-referrer-when-downgrade **Response http header from Spring Boot** Connection: close Content-Length: 0 Date: Mon, 20 Apr 2020 13:13:02 GMT **Request http header from Swagger** accept: application/json;charset=UTF-8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6,ja;q=0.5 Connection: keep-alive Content-Length: 484098 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryiXmuHnaNthhXowmb Cookie: _ga=GA1.2.1299976434.1580821082; JSESSIONID=2C157019D6560405CC75A5F5083DE0AE Host: example.com:8443 Origin: https://example.com:8443 Referer: https://example.com:8443/swagger-ui.html Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36
Résultat du test Swagger:
import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.SwaggerDefinition; import io.swagger.annotations.Tag; import java.util.Collections; import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @Slf4j @RestController @RequestMapping(value = "/v1/fileupload") @Api(tags = {"fileupload api"}, value = "fileupload") @SwaggerDefinition(tags = { @Tag(name = "fileupload api", description = "apis for file upload") }) public class FileUploadController { @Autowired private FileUploadService fileUploadService; private ApiUtilHelper helper = new ApiUtilHelper(); @ApiOperation(value = "upload single data import file") @RequestMapping( value = "/dataimport", method = RequestMethod.POST,, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_UTF8_VALUE } ) public ResponseEntity<?> uploadSingleFileForDataImport(@RequestParam("file") MultipartFile file) throws FileStorageException { log.info("Enter into uploadSingleFileForDataImport"); FileUploadResponse fileUploadResponse = fileUploadService.storeFile(file, "dataImport"); Map<String, Object> additionals = Collections.singletonMap("filupload", fileUploadResponse); BasicResponse br = helper.createSuccessBaseResponse(ApiSuccessCode.CreateSuccess, additionals); return new ResponseEntity<BasicResponse>(br, ApiSuccessCode.CreateSuccess.getHttpStatus()); }
2020.04.20 13:44 (heure UTC) Complément d'information comme ci-dessous: Merci @nbalodi, Quand j'ai configuré logging.level.org.springframework.web = DEBUG. J'ai maintenant le journal des erreurs. Journaux joints comme ci-dessous:
# SSL setup server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=abcdef server.ssl.key-store-type=PKCS12 server.ssl.key-alias=tomcat server.ssl.enabled-protocols=TLSv1.1,TLSv1.2 server.http2.enabled=true security.basic.enabled=false security.enable-csrf=false ## MULTIPART (MultipartProperties) # Enable multipart uploads spring.servlet.multipart.enabled = true # Threshold after which files are written to disk. spring.servlet.multipart.file-size-threshold=2KB # Max file size. spring.servlet.multipart.max-file-size=100MB # Max Request Size spring.servlet.multipart.max-request-size=115MB
La partie étrange est que cette situation d'erreur ne se produit que lorsque nous utilisons les paramètres SSL comme je l'ai décrit ci-dessus.
3 Réponses :
Est-il possible de changer votre niveau de journalisation en DEBUG? ie logging.level.org.springframework.web = DEBUG.
Merci @nbalodi, quand j'ai configuré logging.level.org.springframework.web = DEBUG. J'ai maintenant le journal des erreurs. Journaux joints comme ci-dessous: HttpEntityMethodProcessor: Aucune correspondance pour [application / json; charset = UTF-8], pris en charge: [] ExceptionHandlerExceptionResolver: Resolved [org.springframework.web.multipart.support.MissingServletReq uestPartException file: Obligatoire n'est pas présent] DispatcherServlet: Terminé 400 BAD_REQUEST La partie étrange est que cette situation d'erreur ne se produit que lorsque nous utilisons les paramètres ssl comme je l'ai décrit ci-dessus.
@Tina visite ce fil, il semble avoir le même problème que vous rencontrez. stackoverflow.com/questions/31178160/...
Essayez ceci peut vous aider. Impossible de voir tout autre problème avec votre code.
@RequestParam("file") MultipartFile[] submissions
devrait être
@RequestBody MultipartFile[] submissions
Les fichiers ne sont pas le corps de la demande, ils en font partie et il n'y a pas de HttpMessageConverter
qui puisse convertir la demande en un tableau de MultiPartFile
.
Vous pouvez également utiliser MultipartHttpServletRequest
, qui vous donne accès aux en-têtes des différentes parties.
Merci à tous la réponse. Je pense que c'est le bogue de SpringBoot ou son bogue intégré Tomcat dans la version SpringBoot v2.1.x. Lorsque la version officielle de SpringBoot v2.3.0 est sortie. J'utilise le même code pour passer à la v2.3.0 Tout est maintenant réalisable. J'utilise un test en masse ou appelé test de pression dans le téléchargement de fichiers. C'est 100% réussi maintenant.
Mise à jour: La cause première est que le composant Tomcat n'est pas stable avec le framework Spring - Multipart sous la sécurité https et / ou http2 ou Spring (comme OAuth2) activée.
Dans la plupart des cas, dans Spring Boot 2.3.0 - 2.3.2, le taux d'échec du téléchargement de fichiers est de 4 ~ 14 ~ 50%. Après la version Spring Boot 2.3.5 à 2.4.0, le taux d'échec du téléchargement de fichiers est proche de 50%. La clé différente est la version Tomcat et la version Spring Security est différente parmi ces versions Spring Boot.
Un autre problème est que le protocole http2 pris en charge par Tomcat n'est pas stable. Si vous activez http2 (par exemple, configurez le serveur.http2.enabled = true dans votre fichier de propriétés) et utilisez Multipart ou HttpServletRequest pour le téléchargement de votre fichier, le taux d'échec passe à près de 90% et la connexion est établie.
Conclusion: pour toute personne confrontée au problème de téléchargement de fichier instable et obtenir ERR_CONNECTION_CLOSED et trouver le journal des erreurs sur
org.apache.catalina.connector.ClientAbortException: org.apache.coyote.CloseNowException: connexion [{0}], flux [{1}], ce flux n'est pas accessible en écriture
Causé par: org.apache.coyote.CloseNowException: connexion [{0}], flux [{1}], ce flux n'est pas accessible en écriture
Causé par: org.apache.coyote.http2.StreamException: connexion [{0}], flux [{1}], ce flux n'est pas accessible en écriture
Vous pouvez essayer de mettre à niveau vers Spring Boot 2.4.0 et désactiver la prise en charge http2 de Tomcat dans Spring Boot en configurant le serveur.http2.enabled = false dans votre fichier de propriétés
Vous constaterez peut-être que la stabilité est améliorée même à un taux de réussite de 100%. (J'ai essayé et mis en œuvre à tous mes clients)
Si la désactivation de la prise en charge de http2 ne fonctionne pas pour vous. Vous pouvez essayer de revenir à la version Spring Boot 2.3.0 - 2.3.2 ou d'implémenter votre téléchargement de fichier par HttpServletRequest (n'oubliez pas de désactiver le Multipart dans Spring Boot en premier)
Vous pouvez trouver des documents de développement associés ici et là
salut @Tina. Je suis également confronté au même problème. Utilisez-vous également Spring Auth dans votre projet? Parce que sans SpringAuth, ma requête en plusieurs parties fonctionne correctement, mais lorsque je commence à utiliser Auth, la requête renvoie une erreur 400