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文档中看到过这方面的提示,但没有什么明显的。那个配置是什么?
答案 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。
希望它可以帮到你, 亨利