【问题标题】:Restlet Content Type NegotiationRestlet 内容类型协商
【发布时间】:2015-08-06 05:18:03
【问题描述】:

API 支持各种形式的内容协商是很常见的:请求上的Accept HTTP 标头,请求上的Content-Type HTTP 标头(尽管我认为不符合标准),并从文件扩展名。我希望我的 Restlet REST API 支持所有这些,我正在寻求帮助来弄清楚如何做到这一点。

我的第一个尝试是查看 Restlet 是否支持开箱即用。我正在使用 Jackson 扩展,所以我创建了一个简单的应用程序,将 /foo 路由到 ServerResource,返回 Map<String,Boolean>

当我简单地与/foo 建立一个 GET HTTP URL 连接(例如https://stackoverflow.com/a/953697/27561)时,我得到了 XML。我希望这个默认为 JSON。这就是问题#1。 如何使默认类型为 JSON?

当我对/foo.xml/foo.json 进行相同的HTTP URL 连接调用时,我得到一个404。这是问题2。 如何使用文件扩展名来表示预期的媒体类型?

由于我在 Servlet 容器中运行,我目前的方法是包装 HttpServletRequest,如果没有文件扩展名,则将 Accept HTTP 标头设置为 application/json。这是目前正在解决问题 #1 的 hack。但是,我无法以摆脱问题 #2 中的 404 的方式扩展此方法。

Restlet 使许多其他事情变得简单,以至于我假设我遗漏了一些东西——有些配置存在问题,我可以在某处进行调整以使其做正确的事。我在 API 文档中看到了有关这方面的提示,但没有什么明显的。那是什么配置呢?

【问题讨论】:

标签: java mime-types content-type restlet media-type


【解决方案1】:

最简单的方法是在应用程序的路由器前面添加一个自定义过滤器来执行以下操作:

  • 如果接受的媒体类型列表为空 (request.clientInfo.acceptedMediaTypes),则设置默认媒体类型。标头 Accept 的值在此处设置。在执行服务器资源之前设置它很重要,以便在从 bean 转换为表示时考虑到这一点。

    Filter preferencesFilter = new Filter(getContext()) {
        protected int beforeHandle(Request request, Response response) {
            if (request.getClientInfo().getAcceptedMediaTypes().isEmpty()) {
                request.getClientInfo().accept(MediaType.APPLICATION_JSON);
            } else if ((request.getClientInfo().getAcceptedMediaTypes().size() == 1)
                && (request.getClientInfo().getAcceptedMediaTypes().get(0).getMetadata().equals(MediaType.ALL))) {
                request.getClientInfo().accept(MediaType.APPLICATION_JSON);
            }
            return super.beforeHandle(request, response);
        }            
    }
    

    有关信息,当指定不接受媒体类型时,Restlet 使用已注册的第一个转换器来实际构建响应内容。在你的情况下,它似乎是 XML 的。

  • 检测提供的扩展以在您的情况下推断相应的接受媒体类型。 Restlet 的TunnelService 允许预处理请求以支持使用扩展进行内容协商等功能。您可以简单地按如下所述进行配置:

    public class MyApplication extends Application {
        public MyApplication() {
            getTunnelService().setExtensionsTunnel(true);
        }
    
        @Override
        public Restlet createInboundRoot() {
            (...)
        }
    }
    

否则,您在使用 Restlet 时不应依赖 servlet API。 servlet 扩展只应被视为将 Restlet 应用程序嵌入到 servlet 容器中的适配器...

它在以下地址为您的用例添加了一个示例项目:https://github.com/templth/restlet-stackoverflow/tree/master/restlet/test-restlet-conneg

希望对你有帮助 蒂埃里

【讨论】:

  • "否则,您在使用 Restlet 时应该依赖 servlet API。"您的意思是“否则,在使用 Restlet 时不应依赖 Servlet API。”?
猜你喜欢
  • 2014-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多