Multipart/formdata zwischen Spring Boot Services


#1

Hallo zusammen,

ich habe das Problem ein File von einem Spring Boot Service an einen zweiten Spring Boot Service via REST weiterzuleiten. Ich benutze ausschließlich Spring Boot. Ich habe einen (Ziel) Restendpunkt, der so aussieht:

Restenpunkt der das file annehmen soll

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/tests/api")
public class TestVehicleRegistrationController {
    @PostMapping
    public ResponseEntity<ApiResult> handlePicture(@RequestParam("file") MultipartFile multipartFile) {
        return ResponseEntity.ok(new ApiResult());
    }
}

Dieser Endpunkt funktioniert auch hervorragend via Postman:
grafik

Nun möchte ich diesen Endpunkt aus einem anderen Spring Boot Service aus nutzen:

Code, der den Restendpunkt nutzen möchte

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.set("apikey", config.getApikey());

MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", new ByteArrayResource(new byte[100]));
body.add("apikey", "test");

HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
String destinationUrl = config.getApiurl() + "/api"; //liefert "/tests/api"
RestTemplate restTemplate = new RestTemplate();
ParameterizedTypeReference<ApiResult> responseType = new ParameterizedTypeReference<ApiResult>() {};
ResponseEntity<ApiResult> response = restTemplate.exchange(destinationUrl, HttpMethod.POST, requestEntity, responseType);

return response.getBody();

Nun kommt im Ziel Service ein Warning: Required request part ‘file’ is not present und der aufrufende Service fliegt mit ner Exception raus: org.springframework.web.client.HttpClientErrorException$BadRequest: 400 null

Leider findet man im Netz nie beide Codebeispiele im Zusammenspiel und immer nur einzeln (consume / produce) und mich wundert es schon, dass zwei Spring Technologien nach Standard gebaut (sofern ich in meinem Code keinen Fehler habe :smiley: ) nicht zusammenarbeiten. Ich bin auch schon eine Ebene tiefer gegangen und habe mir den Inhalt vom HttpServletRequest angesehen:

ServletRequest

@PostMapping
public ResponseEntity<ApiResult> handleTest(HttpServletRequest req){
    log.warn("servlet request {}",req.toString());
}

Interessanterweise füllt Postman (mit dem der Request ja funktioniert) das Attribut multipartFiles … Das Resttemplate schickt offensichtlich seine Daten im Attribut mulitpartParameterNames ins HttpServletRequest. In beiden Fällen sind die Daten korrekt drin, aber im Falle vom Spring Resttemplate landet es scheinbar im falschen Attribut.

Seht ihr, was ich hier falsch mache?


#2

Hier ein Screenshot vom falsch befüllten HttpServletRequest:
grafik
Zeigt den Call vom Spring Resttemplate, welcher nicht funktioniert.

Bei Spring Resttemplate (nicht funktionierende Variante): Rot ist befüllt und grün leer.
Bei Postman (Funktionierende Variante): Grün befüllt, rot leer (dieselben Daten)


#3

ist das hier eine Variante mit beidem?
https://www.logicbig.com/tutorials/spring-framework/spring-integration/rest-template-file-upload.html


#4

sorry für die späte antwort … es ist weihnachtsfeier zeit :slight_smile:

ja, das sieht genau nach etwas aus, was ich gesucht habe. Wie hast du es gefunden? Und es funktioniert sogar auf Anhieb. Danke dir.
Ich bin jetzt am auseinanderziehen, was bei mir anders ist. Mal schaun. Werde mich melden, wenn ich was habe.


#5

Der Unterschied ist offensichtlich, was für eine Instanz von “Resource” ich in die MultiValueMap gebe. Ist es eine ByteArrayresource, geht es nicht … bei einer FileSystemResource geht es. Sehr interessant.