可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This returns 200 OK with Content-Length: 0
@RestController
public class RepoController {
@RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
public Object getDocument(@PathVariable long id) {
return null;
}
}
Simply put I'd like it to return 204 No Content on null.
Is there a way to force spring-mvc/rest to return 204 on null not 200? I dont want to change every rest method to return ResponseEntity or something like that, only map null to 204
回答1:
Of course yes.
Option 1 :
@RestController
public class RepoController {
@RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
public Object getDocument(@PathVariable long id, HttpServletResponse response) {
Object object = getObject();
if( null == object ){
response.setStatus( HttpStatus.SC_NO_CONTENT);
}
return object ;
}
}
Option 2 :
@RestController
public class RepoController {
@RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
public Object getDocument(@PathVariable long id) {
Object object = getObject();
if ( null == object ){
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}
return object ;
}
}
Might have typos, but you get the concept.
回答2:
You can use the @ResponseStatus annotation. This way you can have a void method and you don't have to build a ResponseEntity.
@DeleteMapping(value = HERO_MAPPING)
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long heroId) {
heroService.delete(heroId);
}
BTW returning 200 when the object exists and 204 otherwise it's a bit unusual regarding API REST design. It's common to return a 404 (not found) when the requested object is not found. And this can be achieved using an ControllerAdvice.
In Spring REST it's better to handle Exceptions with a Exception handler instead of putting logic to decide the response status, etc. This is an example using the @ControllerAdvice annotation: http://www.jcombat.com/spring/exception-handling-in-spring-restful-web-service
回答3:
I solved this problem with a filter. It's global and simple.
package your.package.filter;
import org.springframework.http.HttpStatus;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class NoContentFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(httpServletRequest, httpServletResponse);
if (httpServletResponse.getContentType() == null ||
httpServletResponse.getContentType().equals("")) {
httpServletResponse.setStatus(HttpStatus.NO_CONTENT.value());
}
}
}
and add the following in your web.xml
<filter>
<filter-name>restNoContentFilter</filter-name>
<filter-class>your.package.filter.NoContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>restNoContentFilter</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
回答4:
You can try this :
@RestController
public class RepoController {
@RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
public ResponseEntity<String> getDocument(@PathVariable long id) {
if(noError) {
............
return new ResponseEntity<String>(HttpStatus.OK);
}
else {
return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
}
}
}
Uou need to change HttpStatus.BAD_REQUEST with the equivalent for 204 code status
回答5:
Same answer but solved by AOP:
@Aspect
public class NoContent204HandlerAspect {
@Pointcut("execution(public * xx.xxxx.controllers.*.*(..))")
private void anyControllerMethod() {
}
@Around("anyControllerMethod()")
public Object handleException(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
Optional<HttpServletResponse> response = Arrays.asList(args).stream().filter(x -> x instanceof HttpServletResponse).map(x -> (HttpServletResponse)x).findFirst();
if (!response.isPresent())
return joinPoint.proceed();
Object retVal = joinPoint.proceed();
if (retVal == null)
response.get().setStatus(HttpStatus.NO_CONTENT.value());
return retVal;
}
}
回答6:
Question is old but for those that needs a global answer and have Spring 4+, you can create a ResponseBodyAdvice that changes response code base on the controller response. The following exemple do it for all @RestController classes :
@ControllerAdvice(annotations = { RestController.class })
public class NullToNoContentResponseBodyAdvice
implements ResponseBodyAdvice<Object>
{
/**
* {@inheritDoc}
*/
@Override
public Object beforeBodyWrite(final Object p_responseBodyObject, final MethodParameter p_methodParameter,
final MediaType p_mediaType, final Class<? extends HttpMessageConverter<?>> p_class,
final ServerHttpRequest p_serverHttpRequest,
final ServerHttpResponse p_serverHttpResponse)
{
// ------------------------- DECLARE -------------------------- //
if (p_responseBodyObject == null)
{
p_serverHttpResponse.setStatusCode(HttpStatus.NO_CONTENT);
}
// Always return object unchanged or it will break response
return p_responseBodyObject;
}
/**
* {@inheritDoc}
*/
@Override
public boolean supports(final MethodParameter p_methodParameter, final Class<? extends HttpMessageConverter<?>> p_class)
{
return AbstractGenericHttpMessageConverter.class.isAssignableFrom(p_class);
}
}