Marcin Sobejko
Marcin Sobejko

Reputation: 23

How to receive multipart or payload data on GET request in spring web-flux controller

We are currently rewriting some legacy service to spring framework with web-flux. Because legacy logic allows receiving payload or multipart data on GET request, we need to recreate that behavior in our new service.

Web-flux doesn't allow us to receive payload or multipart data in case of Get request. I tested this behavior in @RestController and @Controller. Is it possible to change configuration for web-flux to be able to handle such cases?

Example of UploadFileController:

@Controller
public class UploadController {

    @GetMapping(value = "/upload")
    public @ResponseBody Mono<ResponseEntity<String>> upload(@RequestBody Flux<Part> parts) {
        System.out.println("Upload controller was invoked");
        return parts.next()
            .flatMap(part -> DataBufferUtils.join(part.content()))
            .map(this::mapDataBufferToByteArray)
            .map(data -> {
                String uploadedData = new String(data);
                System.out.println("Uploaded file data: " + uploadedData);
                return ResponseEntity.ok(uploadedData);
            });
    }

    private byte[] mapDataBufferToByteArray(DataBuffer buffer) {
        byte[] data = new byte[buffer.readableByteCount()];
        buffer.read(data);
        return data;
    }
}

public class UploadControllerTest {

    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    public void shouldUpload() {
        // given
        final HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);

        LinkedMultiValueMap<String, Object> parameters = new 
        LinkedMultiValueMap<>();
        parameters.add("file", "Test");

        // when
        ResponseEntity<String> response = 
        testRestTemplate.exchange("/upload",
                HttpMethod.GET,
                new HttpEntity<>(parameters, httpHeaders),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }
}

Upvotes: 0

Views: 1096

Answers (1)

Nonika
Nonika

Reputation: 2570

What about creating webfilter which will transform incoming get requests into post internally

@RestController
public static class GetPostHandler {
    @PostMapping("/test")
    public Flux<String> getName(@RequestPart("test") String test, @RequestPart("test2") String test2) {
      return Flux.just(test,test2);
    }
}


@Component
public class GetPostFilter implements WebFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange,
                             WebFilterChain webFilterChain) {
        ServerHttpRequest req = serverWebExchange.getRequest().mutate().method(HttpMethod.POST).build();

        return webFilterChain.filter( serverWebExchange.mutate().request(req).build());
    }
}

I have tested

curl -X GET \
  http://localhost:8080/test \
  -H 'cache-control: no-cache' \
  -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
  -F test=1 \
  -F test2=2

and result is correct:

12

Upvotes: 2

Related Questions