Mic*_*l-O 3 java mapping jersey media-type jersey-2.0
我已经配置了MEDIA_TYPE_MAPPINGS我的 Jersey 应用程序。不幸的是,这会给我的应用程序中的通用上传服务带来一些麻烦。
@PUT
@Path("files/{filename}")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Response uploadFile(
@PathParam("filename") @NotNull @Size(max = 240) String filename, DataSource dataSource)
Run Code Online (Sandbox Code Playgroud)
如果有人上传,.../files/file.xml扩展名就会被删除。
有没有办法告诉 Jersey 跳过对此资源的过滤?
编辑:在 peeskillet 的回答之后,我的假设得到了证实。我已提交改进请求:https ://java.net/jira/browse/JERSEY-2780
首先,这绝不是一个错误。这是预期的行为。媒体类型映射的目的与处理文件无关,而是一种内容协商的替代形式,用于设置标头可能不可用的情况(例如在浏览器中)。
\n尽管官方规范中没有此功能,但该功能是规范最终发布之前草案的一部分。大多数实现决定以某种方式包含它。Jersey 恰好让你配置它。所以可以在规范中看到3.7.1请求预处理
\n\n\n\n
\n- 放
\n
M={config.getMediaTypeMappings().keySet()}L={config.getLanguageMappings().keySet()}m=nulll=null\n\n\n
\n- 对于最终路径段中的每个扩展名(一个
\n.字符后跟一个或多个字母数字字符),从右到左扫描:e
em是null并且e是 的成员,M则从有效请求 URI 中删除相应的扩展并设置m = e。lisnull并且e是 的成员,L则从有效请求 URI 中删除相应的扩展并设置l = e。否则转到步骤 4\n\n\n
\n- 如果 m 不为空,则将 Accept 标头的值设置为
\nconfig.getExtensionMappings().get(m)
3(b) 基本上是说应该从请求的 URI 中删除扩展名,而 4 则说明应该有一些扩展名映射将json(扩展名)映射到application/json并将其设置为Accept标头。您可以从不同的测试中看到这种行为
@POST\n@Path("/files/{file}")\n@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})\npublic Response doTest(@PathParam("file") String fileName, @Context HttpHeaders headers) {\n String accept = headers.getHeaderString(HttpHeaders.ACCEPT);\n return Response.ok(fileName + "; Accept: " + accept).build();\n}\n...\n\nMap<String, MediaType> map = new HashMap<>();\nmap.put("xml", MediaType.APPLICATION_XML_TYPE);\nresourceCnfig.property(ServerProperties.MEDIA_TYPE_MAPPINGS, map);\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n
curl -v http://localhost:8080/api/mapping/files/file.xml -X POST
\n结果:file; Accept: application/xml
如果我们注释掉该配置属性,您将看到Accept标头尚未设置。
\n\n\n
curl -v http://localhost:8080/api/mapping/files/file.xml -X POST
\n结果:file.xml; Accept: */**
当您配置 时ServerProperties.MEDIA_TYPE_MAPPINGS,org.glassfish.jersey.server.filter.UriConnegFilter是用于此功能的过滤器。您可以在源代码第 162 和 179 行中看到,过滤器正在剥离扩展名
path = new StringBuilder(path).delete(index, index + suffix.length() + 1).toString();\n...\nrc.setRequestUri(uriInfo.getRequestUriBuilder().replacePath(path).build(new Object[0]));\nRun Code Online (Sandbox Code Playgroud)\n所以没有办法配置它(至少据我从源代码中可以看出),所以我们必须扩展该类,重写该filter方法并至少取出实际上的最后一行进行更换,然后注册过滤器。这就是我为让它发挥作用所做的事情。我只需复制并粘贴过滤器中的代码,并注释掉它替换扩展名的行
import java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\nimport javax.annotation.Priority;\nimport javax.ws.rs.container.ContainerRequestContext;\nimport javax.ws.rs.container.PreMatching;\nimport javax.ws.rs.core.Configuration;\nimport javax.ws.rs.core.Context;\nimport javax.ws.rs.core.MediaType;\nimport javax.ws.rs.core.PathSegment;\nimport javax.ws.rs.core.UriInfo;\nimport org.glassfish.jersey.server.filter.UriConnegFilter;\n\n@PreMatching\n@Priority(3000)\npublic class MyUriConnegFilter extends UriConnegFilter {\n\n public MyUriConnegFilter(@Context Configuration config) {\n super(config);\n }\n \n public MyUriConnegFilter(Map<String, MediaType> mediaTypeMappings, \n Map<String, String> languageMappings) {\n super(mediaTypeMappings, languageMappings);\n }\n\n @Override\n public void filter(ContainerRequestContext rc)\n throws IOException {\n UriInfo uriInfo = rc.getUriInfo();\n\n String path = uriInfo.getRequestUri().getRawPath();\n if (path.indexOf(\'.\') == -1) {\n return;\n }\n List<PathSegment> l = uriInfo.getPathSegments(false);\n if (l.isEmpty()) {\n return;\n }\n PathSegment segment = null;\n for (int i = l.size() - 1; i >= 0; i--) {\n segment = (PathSegment) l.get(i);\n if (segment.getPath().length() > 0) {\n break;\n }\n }\n if (segment == null) {\n return;\n }\n int length = path.length();\n\n String[] suffixes = segment.getPath().split("\\\\.");\n for (int i = suffixes.length - 1; i >= 1; i--) {\n String suffix = suffixes[i];\n if (suffix.length() != 0) {\n MediaType accept = (MediaType) this.mediaTypeMappings.get(suffix);\n if (accept != null) {\n rc.getHeaders().putSingle("Accept", accept.toString());\n\n int index = path.lastIndexOf(\'.\' + suffix);\n path = new StringBuilder(path).delete(index, index + suffix.length() + 1).toString();\n suffixes[i] = "";\n break;\n }\n }\n }\n for (int i = suffixes.length - 1; i >= 1; i--) {\n String suffix = suffixes[i];\n if (suffix.length() != 0) {\n String acceptLanguage = (String) this.languageMappings.get(suffix);\n if (acceptLanguage != null) {\n rc.getHeaders().putSingle("Accept-Language", acceptLanguage);\n\n int index = path.lastIndexOf(\'.\' + suffix);\n path = new StringBuilder(path).delete(index, index + suffix.length() + 1).toString();\n suffixes[i] = "";\n break;\n }\n }\n }\n if (length != path.length()) {\n //rc.setRequestUri(uriInfo.getRequestUriBuilder().replacePath(path).build(new Object[0]));\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n然后配置一下
\nMap<String, MediaType> map = new HashMap<>();\nmap.put("xml", MediaType.APPLICATION_XML_TYPE);\nmap.put("json", MediaType.APPLICATION_JSON_TYPE);\nresourceConfig.register(new MyUriConnegFilter(map, null));\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n
curl -v http://localhost:8080/api/mapping/files/file.xml -X POST
\n结果:file.xml; Accept: application/xml
\n\n\n
curl -v http://localhost:8080/api/mapping/files/file.json -X POST
\n结果:file.json; Accept: application/json
| 归档时间: |
|
| 查看次数: |
1208 次 |
| 最近记录: |