簡體   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