Restlet内容类型谈判

时间:2015-05-24 17:24:21

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

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

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

当我只是简单地进行GET HTTP URL连接(la https://stackoverflow.com/a/953697/27561)到/foo时,我找回了XML。我想这个默认为JSON。这是问题#1。 如何制作默认类型JSON?

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

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

Restlet让很多其他东西变得容易,我假设我错过了一些东西 - 有些问题我可以调整某些配置以使其做正确的事情。我在API文档中看到过这方面的提示,但没有什么明显的。那个配置是​​什么?

1 个答案:

答案 0 :(得分:3)

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

  • 如果接受的媒体类型列表为空(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扩展只应被视为在Servlet容器中嵌入Restlet应用程序的适配器......

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

希望它可以帮到你, 亨利