web-dev-qa-db-fra.com

Renvoie HTTP 204 sur null avec spring @RestController

Cela renvoie 200 OK avec Content-Length: 0

@RestController
public class RepoController {
    @RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
    public Object getDocument(@PathVariable long id) {
       return null;
    }

}

Autrement dit, je voudrais qu'il renvoie 204 Aucun contenu sur null.

Existe-t-il un moyen de forcer spring-mvc/rest à retourner 204 sur null et non 200? Je ne veux pas changer chaque méthode de repos pour retourner ResponseEntity ou quelque chose comme ça, mapper uniquement null à 204

21
user1606576

Bien sûr que oui.

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 ;
    }
}

Pourrait avoir des fautes de frappe, mais vous obtenez le concept.

22
Karthik R

Vous pouvez utiliser l'annotation @ ResponseStatus . De cette façon, vous pouvez avoir une méthode void et vous n'avez pas à créer de ResponseEntity.

@DeleteMapping(value = HERO_MAPPING)
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long heroId) {
    heroService.delete(heroId);
}

BTW renvoyant 200 lorsque l'objet existe et 204 sinon c'est un peu inhabituel concernant l'API REST design. Il est courant de renvoyer un 404 (non trouvé) lorsque l'objet demandé n'est pas trouvé. Et cela peut être obtenu à l'aide d'un ControllerAdvice.

Au printemps REST il est préférable de gérer les exceptions avec un gestionnaire d'exceptions au lieu de mettre de la logique pour décider de l'état de la réponse, etc. Ceci est un exemple utilisant l'annotation @ControllerAdvice: http://www.jcombat.com/spring/exception-handling-in-spring-restful-web-service

38
spekdrum

J'ai résolu ce problème avec un filtre. C'est global et 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());
        }
    }
}

et ajoutez ce qui suit dans votre 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>
9
mahieus

Vous pouvez essayer ceci:

@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);
       }
   }
}

Vous devez modifier HttpStatus.BAD_REQUEST avec l'équivalent pour l'état du code 204

4
Bilal BBB

Même réponse mais résolue par 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;
  }
}
1
Marek Raszewski