OpenFeign / feign

Feign makes writing java http clients easier
Apache License 2.0
9.5k stars 1.93k forks source link

Can't set Content-type for Request Header when use Spring annotations #1239

Open sdlzhd opened 4 years ago

sdlzhd commented 4 years ago

I'm using Feign and Spring annotations, I have a request that expects to accept "text/plain".

@PostMapping(value = "/demo", consumes = "application/json", produces="text/plain")
public String demo(@RequestBody List<Long> ids);

But, the produces value not working. The request still has a header: Accept=application/json

finnetrolle commented 4 years ago

May be I got it wrong but your request produces (send using) text/plain and consumes (wait for result) app/json. Looks like "Accept=application/json" is ok here.

velo commented 4 years ago

@sdlzhd are you using feign-spring4 or feign support from springboot?

sdlzhd commented 4 years ago

I am using feign + feign-spring4 in the client app. In the server side, use spring boot.

I found the cause of the problem.

As you see the method declaration, the request template is Accept = "application/json", Content-Type="application/json".

My expected result is Accept = "text/plain", Content-Type="application/json" in client.

In the server side, the Controller:

@PostMapping(value = "/demo")
public String demo(@RequestBody List<Long> ids);

The server will accept a Content-Type = "application/json" request and return a Content-Type='text/plain' reponse.

The key to this problem is that when parsing @RequestBody, the wrong header is set. I think for the client, @RequestBody should be parsed as Content-Type="application/json", not Accept.

For the client, the best resolution order is:

  1. @RequestBody => Content-Type
  2. produces => Accept
  3. consumes => Content-Type

This will be easily consistent with Spring Boot.

sdlzhd commented 4 years ago

Any reply?

plnordquist commented 4 years ago

I just ran into this issue on my own project, I believe the lines below seem to assume if you use the RequestBody annotation it should be handled the same as the produces declaration in the RequestMapping. https://github.com/OpenFeign/feign/blob/ae514aaf790c87804b245013044bd212d3786b92/spring4/src/main/java/feign/spring/SpringContract.java#L94-L96 I was able to ignore adding the RequestBody annotation on my contract interface and that seemed to work around this issue and still serialize a single request parameter as a json object in the request body and respect the produces field of my RequestMapping annotation. I didn't test if this work around is viable on a multiple parameter method call.

kdavisk6 commented 3 years ago

We'll need to look into this more, but if anyone here is interested in taking this up, please do.

zwyStyle commented 3 years ago

I think that when use @RequestBody , the server side should accept the Content-Type = "application/json" request. Here are some of my points:

lushaorong commented 2 years ago

If it hasn't been solved, I want to try it

velo commented 2 years ago

I can't say if was fixed or not, feel free to take a look