Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Status code 404 turns into status code 406 when accept header is put to application/xml #13163

Closed
desmethans opened this issue May 14, 2018 · 7 comments
Labels
status: declined A suggestion or change that we don't feel we should currently apply

Comments

@desmethans
Copy link

desmethans commented May 14, 2018

When your application gets a request and throws a ResponseStatusException(HttpStatus.NOT_FOUND) the response has a status code 404 and a JSON body when no accept header is provided.

When your application gets a request and throws a ResponseStatusException(HttpStatus.NOT_FOUND) the response has a status code 404 and a JSON body when the accept header is put to application/json

When your application gets a request and throws a ResponseStatusException(HttpStatus.NOT_FOUND) the response has a status code 406 and no body when the accept header is put to application/xml.

A demo can be found on https://github.com/desmethans/responsestatusexceptionboot.git
and can be seen with curl http://localhost:8080/persons/2 --header "accept:application/xml" -i

A Spring application without Spring boot does not have this problem as demoed on https://github.com/desmethans/responsestatusexception.git

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label May 14, 2018
@wilkinsona
Copy link
Member

Thanks for the sample. The difference in behaviour is caused by Spring Boot's white label error page which aims to return something more useful out of the box than the empty body that you get with your Spring Framework-based example. With no Accept header, Boot's error controller will return JSON:

{"timestamp":"2018-05-14T13:28:46.854+0000","status":404,"error":"Not Found","message":"Response status 404","path":"/persons/2"}

It can also return HTML:

<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>Mon May 14 14:30:24 BST 2018</div><div>There was an unexpected error (type=Not Found, status=404).</div><div>Response status 404</div></body></html>

When you ask for XML, an attempt is made to convert the same POJO that produces the above JSON response into XML. You application does not include any dependencies that are capable of producing XML from a POJO so Spring MVC deems the requested media type to be unacceptable and responds with a 406.

You can disable ErrorMvcAutoConfiguration to restore embedded Tomcat's default behaviour. This will leave you with a 404 response to a request that only accepts application/xml but it will have an HTML body.

The ideal would, perhaps, be to respond with an empty body if the error controller's response cannot be written in an acceptable media type. However, I'm not sure that it's possible with Spring MVC.

@bclozel knows more about this than I do so he may have some suggestions.

@wilkinsona wilkinsona added the for: team-attention An issue we'd like other members of the team to review label May 14, 2018
@bclozel
Copy link
Member

bclozel commented May 14, 2018

@wilkinsona is spot on - this is what happens in this case.
We could have a specific converter that writes empty bodies for 404, but we'd be twisting the contract since it only knows about the media type and object itself boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType); - so we can't restrict it to 404 responses.

There might be a way out of this limitation, but such a behavior would still be questionable when considering the RFCs:

  • with a different requested media type, you wouldn't have a different representation of the same resource, but something empty
  • if the HTTP client can only accept a certain media type, HTTP 406 is the correct response to send clients

For web APIs, I'm usually seeing components throwing custom business exceptions (UnknownPersonException) annotated with @ResponseStatus or @ControllerAdvice components turning those into ResponseEntity instances. I'd argue this is easier to test as well.

@wilkinsona
Copy link
Member

Thank you, @bclozel.

@wilkinsona wilkinsona added status: declined A suggestion or change that we don't feel we should currently apply and removed for: team-attention An issue we'd like other members of the team to review status: waiting-for-triage An issue we've not yet triaged labels May 15, 2018
@TobiasPfeifer
Copy link

TobiasPfeifer commented Mar 19, 2019

@bclozel I have a similar problem.
A Controller is registered for path /api/test that produces text/csv. It has a GET-mapping to /existing
When a client calls /api/test/non_existing the response has a status code 406 and no body.
In this case I would expect to get a response with status code 404 and no body.

I can follow the points you gave if a client queries an url that is mapped but the accept-header isn't matching. However I think in this case when there is no mapping the 404 should take precedence with an empty body.

Is there a way to work around this issue without getting a html body but maybe an empty body?

@bclozel
Copy link
Member

bclozel commented Mar 19, 2019

@TobiasPfeifer I you believe this is a bug, please create a new issue with a project reproducing the problem. If this is more of a question, please create a StackOverflow question and feel free to point to it from here. In all cases, a description is not enough and a working sample is always better.

@wangjingfei
Copy link

@TobiasPfeifer I you believe this is a bug, please create a new issue with a project reproducing the problem. If this is more of a question, please create a StackOverflow question and feel free to point to it from here. In all cases, a description is not enough and a working sample is always better.

@bclozel I've encountered the same problem. Is there any issues or StackOverflow pointing here? I'd like to know if it is fixed and when. Thanks

@bclozel
Copy link
Member

bclozel commented Nov 21, 2019

@wangjingfei do you have a sample I can take a look at? If you believe this is a bug, please create a new issue with a sample application reproducing the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: declined A suggestion or change that we don't feel we should currently apply
Projects
None yet
Development

No branches or pull requests

6 participants