繁体   English   中英

如何为 Spring-Boot 请求映射方法设置优先级

[英]How to set priority to Spring-Boot request mapping methods

我有一个带有 RestController 的 Spring-Boot (v2.0.2) 应用程序,它有 2 种方法,它们的区别仅在于 Accept 标头。 代码的简化版本是这样的:

@RestController
@RequestMapping("/myapp")
public class FooController {

    @GetMapping(value = "/foo/{id}", headers = "Accept=application/json", produces = "application/json;charset=UTF-8")
    public ResponseEntity<String> fooJson(@PathVariable id) {
        return foo(pageId, true);
    }

    @GetMapping(value = "/foo/{id}", headers = "Accept=application/ld+json", produces = "application/ld+json;charset=UTF-8")
    public ResponseEntity<String> fooJsonLd(@PathVariable id) {
        return foo(pageId, false);
    }

    private ResponseEntity<String> foo(String id, boolean isJson) {
        String result = generateBasicResponse(id);
        if (isJson) {
            return result
        }
        return addJsonLdContext(result);
    }

这工作正常。 例如,如果我们发送一个带有接受头的请求,例如application/json;q=0.5,application/ld+json;q=0.6 ,它将返回一个 json-ld 响应。

我的问题是,如果我们发送一个没有接受标头、空接受标头或通配符*/*的请求,那么它默认总是返回一个 json 响应,而我希望默认响应是 json-ld。

我尝试了各种方法来使 json-ld 请求映射优先于 json 映射:

  • 颠倒声明映射的顺序。
  • 向两种方法添加@Order 注释(json-ld 的值为 1,json 方法的值为 2)
  • 创建不同的类并将@Order 注释放在类级别
  • Accept=*/*作为第二个接受标头添加到 json-ld 映射确实可以为其提供优先权,但具有不需要的副作用,即所有接受标头都被接受,即使是不受支持的类型,例如application/xml

我能想到的唯一解决方案是创建一个接受两个标头的请求映射方法,然后自己处理接受标头,但我并不喜欢这种解决方案。 有没有更好、更简单的方法来优先使用 json-ld?

对配置自定义 MediaTypes 的这个问题进行了更多搜索之后,我指出了正确的方向。 WebMvcConfigurerAdapter (Spring 3 or 4) 或 WebMvcConfigurer (Spring 5) 允许你像这样设置默认的媒体类型:

public static final String MEDIA_TYPE_JSONLD  = "application/ld+json";

@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.valueOf(MEDIA_TYPE_JSONLD));
    }
}

这对于没有或空的接受头的请求非常有用,以及accept: */* 但是,当您将不受支持的类型与通配符结合使用时,例如accept: */*,text/plain它将返回 json 而不是 json-ld!? 我怀疑这是 Spring 中的一个错误。

我使用@GetMapping注释中的consumes解决了这个问题。 根据官方文档

格式是单个媒体类型或一系列媒体类型,只有当 Content-Type 匹配这些媒体类型之一时才会映射请求。 可以使用“!”否定表达式运算符,如“!text/plain”,它匹配所有内容类型不是“text/plain”的请求。

在下面的解决方案中,请注意我已将消耗数组添加到普通的 json 请求映射中,这使得客户端只能使用具有正确Content-Type的 json 端点。 其他请求转到ld+json端点。

@GetMapping(value = "/json", headers = "Accept=application/json", consumes = {"application/json"})
@ResponseBody
public String testJson() {
    return "{\"type\":\"json\"}";
}

@GetMapping(value = "/json", headers = "Accept=application/ld+json")
@ResponseBody
public String textLDJson() {
    return "{\"type\":\"ld\"}";
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM