首先,這絕不是一個錯誤。這是預期的行爲。媒體類型映射的目的與處理文件無關,而是在設置標題可能不可用的情況下(例如在瀏覽器中)的內容協商的替代形式。
雖然沒有在官方規格中,但該功能是規格最終發佈之前的草稿的一部分。大多數實現決定以這種或那種方式包含它。澤西恰好讓你配置它。所以可以看到here in the spec in 3.7.1 Request Preprocessing
設置
M
= {config.getMediaTypeMappings().keySet()}
L
= {config.getLanguageMappings().keySet()}
m
= null
l
= null
- 其中,config是應用程序提供的ApplicationConfig子類的實例。
對於每個延伸部在從右邊的最後路徑段掃描(一個.
字符後跟一個或多個字母數字字符)e
到左:
- (a)拆下前導字符「」從
e
- (b)若
m
是null
和e
是M
成員然後從有效請求URI中刪除相應的延伸並設置m = e
。
- (c)否則,如果
l
是null
和e
是L
的成員,則從有效請求URI中刪除相應的擴展並設置l = e
。否則到步驟4
如果m不爲空,則Accept首部的值設置爲config.getExtensionMappings().get(m)
圖3(b)基本上是說該擴展應從被刪除所請求的URI和4表明應該有一些擴展映射將映射json
(擴展名)映射到application/json
,並將其設置爲Accept
標題。你可以從不同的測試看,這種行爲
@POST
@Path("/files/{file}")
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response doTest(@PathParam("file") String fileName, @Context HttpHeaders headers) {
String accept = headers.getHeaderString(HttpHeaders.ACCEPT);
return Response.ok(fileName + "; Accept: " + accept).build();
}
...
Map<String, MediaType> map = new HashMap<>();
map.put("xml", MediaType.APPLICATION_XML_TYPE);
resourceCnfig.property(ServerProperties.MEDIA_TYPE_MAPPINGS, map);
curl -v http://localhost:8080/api/mapping/files/file.xml -X POST
結果:file; Accept: application/xml
如果我們註釋掉配置屬性,你會看到Accept
頭有沒有已設置。
curl -v http://localhost:8080/api/mapping/files/file.xml -X POST
結果:file.xml; Accept: */**
話雖這麼說...
在配置ServerProperties.MEDIA_TYPE_MAPPINGS
,在org.glassfish.jersey.server.filter.UriConnegFilter
是用於此功能的過濾器。您可以在source code in line 204 and 211,所述過濾器剝離擴展看到
path = new StringBuilder(path).delete(index, index + suffix.length() + 1).toString();
...
rc.setRequestUri(uriInfo.getRequestUriBuilder().replacePath(path).build(new Object[0]));
所以沒有辦法(至少據我可以查看源告訴)配置這一點,所以我們將不得不延長該類,覆蓋filter
方法並至少取出實際進行替換的最後一行,然後註冊該過濾器。以下是我所做的工作。我簡單地複製和粘貼從過濾器的代碼,並註釋掉它將取代擴展
import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.UriInfo;
import org.glassfish.jersey.server.filter.UriConnegFilter;
@PreMatching
@Priority(3000)
public class MyUriConnegFilter extends UriConnegFilter {
public MyUriConnegFilter(@Context Configuration config) {
super(config);
}
public MyUriConnegFilter(Map<String, MediaType> mediaTypeMappings,
Map<String, String> languageMappings) {
super(mediaTypeMappings, languageMappings);
}
@Override
public void filter(ContainerRequestContext rc)
throws IOException {
UriInfo uriInfo = rc.getUriInfo();
String path = uriInfo.getRequestUri().getRawPath();
if (path.indexOf('.') == -1) {
return;
}
List<PathSegment> l = uriInfo.getPathSegments(false);
if (l.isEmpty()) {
return;
}
PathSegment segment = null;
for (int i = l.size() - 1; i >= 0; i--) {
segment = (PathSegment) l.get(i);
if (segment.getPath().length() > 0) {
break;
}
}
if (segment == null) {
return;
}
int length = path.length();
String[] suffixes = segment.getPath().split("\\.");
for (int i = suffixes.length - 1; i >= 1; i--) {
String suffix = suffixes[i];
if (suffix.length() != 0) {
MediaType accept = (MediaType) this.mediaTypeMappings.get(suffix);
if (accept != null) {
rc.getHeaders().putSingle("Accept", accept.toString());
int index = path.lastIndexOf('.' + suffix);
path = new StringBuilder(path).delete(index, index + suffix.length() + 1).toString();
suffixes[i] = "";
break;
}
}
}
for (int i = suffixes.length - 1; i >= 1; i--) {
String suffix = suffixes[i];
if (suffix.length() != 0) {
String acceptLanguage = (String) this.languageMappings.get(suffix);
if (acceptLanguage != null) {
rc.getHeaders().putSingle("Accept-Language", acceptLanguage);
int index = path.lastIndexOf('.' + suffix);
path = new StringBuilder(path).delete(index, index + suffix.length() + 1).toString();
suffixes[i] = "";
break;
}
}
}
if (length != path.length()) {
//rc.setRequestUri(uriInfo.getRequestUriBuilder().replacePath(path).build(new Object[0]));
}
}
}
該行,然後對其進行配置
Map<String, MediaType> map = new HashMap<>();
map.put("xml", MediaType.APPLICATION_XML_TYPE);
map.put("json", MediaType.APPLICATION_JSON_TYPE);
resourceConfig.register(new MyUriConnegFilter(map, null));
curl -v http://localhost:8080/api/mapping/files/file.xml -X POST
結果:file.xml; Accept: application/xml
curl -v http://localhost:8080/api/mapping/files/file.json -X POST
結果:file.json; Accept: application/json
我知道這不是bug。好的分析,但。我先檢查過濾器,我的審查要求與你一樣。我唯一能做的就是提出一個改進請求。這是一個功能限制。 – 2015-02-09 14:52:23
所以我重讀了你的問題,你想跳過那一個資源。我很好奇,但是決定性因素是什麼?我可以看到註釋的使用,但這需要另一個過濾器,因爲當前使用的過濾器是預先匹配的過濾器,所以我們還不能獲取資源信息。頭部是可能的,但這看起來不太優雅,客戶端必須知道/記得設置該頭部。 – 2015-02-10 09:16:00
我雖然有一些註釋和預處理的想法。雖然,這是很多模糊。通過一個臨時頭管道配置並不理想,我不希望客戶改變任何事情。這純粹是服務器端問題。 – 2015-02-10 09:28:52