Return HTTP 204 on null with spring @RestController

前端 未结 7 2015
旧时难觅i
旧时难觅i 2020-12-25 12:10

This returns 200 OK with Content-Length: 0

@RestController
public class RepoController {
    @RequestMapping(value = \"/document/{id}\", method = RequestMeth         


        
相关标签:
7条回答
  • 2020-12-25 12:42

    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

    0 讨论(0)
  • 2020-12-25 12:43

    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);
        }
    }
    
    0 讨论(0)
  • 2020-12-25 12:48

    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>
    
    0 讨论(0)
  • 2020-12-25 12:56

    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

    0 讨论(0)
  • 2020-12-25 13:02

    you may custom yourself HttpMessageConverter to support this, as i do this , added spring.http.converters.preferred-json-mapper=gson toapplication.properties config file, and a result advice like :

    @ControllerAdvice
    public class CommonResultAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }
    
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
    
        if (null == o) {
        //set http code
            serverHttpResponse.setStatusCode(HttpStatus.NO_CONTENT);
            return BaseResult.success();
        }
    
        if (o instanceof String) {
            ObjectMapper mapper = new ObjectMapper();
            try {
                return mapper.writeValueAsString(BaseResult.success(o));
            } catch (JsonProcessingException ignore) {
            }
        }
    
        if (o instanceof BaseResult) {
            return o;
        }
        return BaseResult.success(o);
    }
    

    }

    or custom a HttpMessageConverter like this:

    @Configuration
    public class BeanConfiguration {
    @Bean
    public HttpMessageConverter resultToJsonConverter() {
        return new GsonHttpMessageConverter();
    }
    }
    

    hope to help you. :)

    0 讨论(0)
  • 2020-12-25 13:03

    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;
      }
    }
    
    0 讨论(0)
提交回复
热议问题