Java 使用 spring @RestController 在 null 上返回 HTTP 204

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32396884/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:28:10  来源:igfitidea点击:

Return HTTP 204 on null with spring @RestController

javaspringspring-mvcspring-restcontroller

提问by user1606576

This returns 200 OK with Content-Length: 0

这将返回 200 OK 内容长度: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.

简单地说,我希望它在 null 上返回 204 No Content。

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

有没有办法强制 spring-mvc/rest 在 null 而不是 200 时返回 204?我不想改变每个休息方法来返回 ResponseEntity 或类似的东西,只将 null 映射到 204

采纳答案by Karthik R

Of course yes.

当然是的。

Option 1 :

选项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 :

选项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.

可能有错别字,但你明白了。

回答by Bilal BBB

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

你需要改变 HttpStatus.BAD_REQUEST 与 204 代码状态的等价物

回答by spekdrum

You can use the @ResponseStatusannotation. This way you can have a void method and you don't have to build a ResponseEntity.

您可以使用@ResponseStatus批注。这样您就可以拥有一个 void 方法,而不必构建一个 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.

顺便说一句,当对象存在时返回 200,否则返回 204,否则对于 API REST 设计来说有点不寻常。当未找到请求的对象时,返回 404(未找到)是很常见的。这可以使用 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

在 Spring REST 中,最好使用异常处理程序处理异常,而不是放置逻辑来决定响应状态等。这是使用 @ControllerAdvice 注释的示例:http: //www.jcombat.com/spring/exception-handling- in-spring-restful-web-service

回答by Marek R

Same answer but solved by AOP:

相同的答案,但由 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;
  }
}

回答by mahieus

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

并在您的 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>

回答by Jean-Daniel FISCHER

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 :

问题很老,但对于那些需要全局答案并拥有 Spring 4+ 的人,您可以创建一个 ResponseBodyAdvice,根据控制器响应更改响应代码。以下示例为所有 @RestController 类执行此操作:

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