当前位置: 首页 > 面试题库 >

在Jersey中限制路径媒体类型映射

毕泽宇
2023-03-14
问题内容

我已经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)

如果有人上传.../files/file.xml,扩展名将被删除。

有没有办法告诉Jersey跳过对此资源的过滤?

编辑
:peeskillet的答案后,我的假设得到确认。我已经提出了改进请求:https
:
//java.net/jira/browse/JERSEY-2780


问题答案:

首先,这绝不是错误。这是预期的行为。媒体类型映射的目的与处理文件无关,而是在内容标头可能不可用的情况下(例如在浏览器中)使用内容协商的另一种形式。

尽管不在正式规范中,但此功能是规范最终发布之前的草案的一部分。大多数实现都决定以一种或另一种方式包含它。泽西碰巧让您对其进行配置。因此可以在3.7.1请求预处理的规范中看到此处

    • M = {config.getMediaTypeMappings().keySet()}
    • L = {config.getLanguageMappings().keySet()}
    • m = null
    • l = null
    • 其中config是ApplicationConfig的应用程序提供的子类的实例
    • 对于最终路径段中从右到左扫描的每个扩展名(一个.字符后跟一个或多个字母数字字符)e

    • (a)删除开头的“。” 来自的字符e

    • (b)如果mis nulleis是的成员,M则从有效请求URI中删除相应的扩展名并设置m = e
    • (c)如果lis是nulleis的成员,L则从有效请求URI中删除相应的扩展名并设置l = e。否则转到步骤4
    • 如果m不为null,则将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_MAPPINGSorg.glassfish.jersey.server.filter.UriConnegFilter就是用于此功能的过滤器。您可以在源代码的204和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



 类似资料:
  • 问题内容: 自数小时以来,我一直在尝试纠正http错误,但它仍显示不支持的页面。我在邮递员中添加标题。 这是我的Java代码 这是我的档案 问题答案: 通过和如何在响应流和请求流之间对对象进行序列化和反序列化。 将会发生的是,将从提供者的注册表中进行搜索,以查找可以处理的媒体类型。如果找不到,则Jersey无法处理该请求,并将发送415不支持的媒体类型。通常,你还应该在服务器端记录一个异常。不知道

  • 问题内容: 我正在尝试简单的Jersey + JSON示例,但出现以下错误 我放入以下jar文件以获得适当的结果 为什么会出现此类错误?错误日志在这里: web.xml JsonExample.java 和Json服务 如果我做错了事,请提出建议。 问题答案: 此问题已通过jersey-bundle-1.8.jar修复

  • 在使用Spring和REST API时,我遇到了一个有趣的问题,这个问题是:在Spring中,路径是否仅限于一定数量的字符? 谢谢你

  • 媒体类型允许你指定文件将如何在不同媒体呈现。该文件可以以不同的方式显示在屏幕上,在纸张上,或听觉浏览器等等。  媒体类型 一些CSS属性只设计了某些媒体。例如"voice-family"属性是专为听觉用户代理。其他一些属性可用于不同的媒体类型。例如,"font-size"属性可用于屏幕和印刷媒体,但有不同的值。屏幕和纸上的文件不同,通常需要一个更大的字体,sans - serif字体比较适合在屏幕

  • 我已经在SO上找到了一些这样的问题,但它们似乎都没有解决我的特定问题,而且我无法自己找到解决方案。 下面是我得到的错误: 我通过一个 jQuery AJAX 请求发送此请求,如下所示: 这是我的Javaendpoint: 我看到一些人很幸运地将endpoint方法的参数更改为使用@FormDataParam而不是FormDataMultiPart(如这里所示),但我无法编辑Java类,因此我必须按

  • 我正在创建一个聊天应用程序,在该应用程序中,我从WhatsApp等图库上传图像和视频,但当我尝试选择WhatsApp文件夹已下载的图像时,我得到了以下路径 但当我读到这篇文章以获得显示图像的真实路径时,我得到了一个例外: java.io.FileNotFound异常:打开失败:ENOENT(没有这样的文件或目录) 这是我的供应商 下面是文件路径 这只发生在WhatsApp媒体上,任何人请告诉我解决