Restlet 条件路由到不同的资源
Restlet conditional routing to different resources
我有一个 POST
请求,我想根据正文内容分配给不同的 Resources
。
如果正文包含一个非空的 token: "token":"1q2w3e4r5t"
那么我想将请求路由到 TokenedResource,
否则路由到 NonTokenResource
.
我想为它使用过滤器 (@beforeHandle
),但过滤器 returns 的唯一指示是 CONTINUE
或 STOP
...
有什么建议吗?
为此,您需要扩展 Restlet 路由。后者负责根据计算的分数确定哪个路由与特定请求匹配。
特别是路由涉及您需要覆盖的两个 class:Router
和 TemplateRoute
。路由器一负责创建模板路由。如果要提供自定义模板路由,则需要提供自定义路由。在自定义模板路由中,您可以实现自己的路由评分算法。
这是自定义路由器的实现:
public class CustomRouter extends InternalRouter {
public CustomRouter(Context context) {
super(context);
setFinderClass(CustomFinder.class);
}
protected TemplateRoute createRoute(String uriPattern,
Restlet target, int matchingMode) {
CustomTemplateRoute result = new CustomTemplateRoute(
this, uriPattern, target);
result.getTemplate().setMatchingMode(matchingMode);
result.setMatchingQuery(getDefaultMatchingQuery());
return result;
}
}
不太容易理解的是为什么我们需要使用方法 setFinderClass
指定自定义查找器。 Restlet 中的查找器负责为每个请求实例化服务器资源。默认实现(class Finder
)的问题在于您无法访问关联的 class (targetClass
)。如果你需要知道它(看起来是这样),你必须提供你自己的实现。我们稍后会重点讨论这个。
有了这个 class,这里是在应用程序中附加服务器资源的方法 class:
@Override
public Restlet createInboundRoot() {
Router router = new CustomRouter(getContext());
router.attach("/test", TokenedResource.class);
router.attach("/test", NonTokenResource.class);
return router;
}
我们必须将它们附加在同一路径上。
这里是自定义模板路由的实现:
public class CustomTemplateRoute extends TemplateRoute {
public CustomTemplateRoute(Restlet next) {
super(next);
}
public CustomTemplateRoute(Router router,
String uriTemplate, Restlet next) {
super(router, uriTemplate, next);
}
public CustomTemplateRoute(Router router,
Template template, Restlet next) {
super(router, template, next);
}
@Override
public float score(Request request, Response response) {
float result = super.score(request, response);
(...)
return result;
}
}
在方法 score
中,如果我们处于对 class TokenedResource
的标记请求的情况下,我们将增加分数,否则将减少。这允许让 Restlet select 为正确的情况提供正确的服务器资源。
在继续之前,请提供 class CustomFinder 的内容:
public class CustomFinder extends Finder {
private Class<? extends ServerResource> targetClass;
public CustomFinder() {
super();
}
public CustomFinder(Context context) {
super(context);
}
public CustomFinder(Context context,
Class<? extends ServerResource> targetClass) {
super(context, targetClass);
this.targetClass = targetClass;
}
}
这是一种实现自定义处理以计算分数的方法:
@Override
public float score(Request request, Response response) {
float result = super.score(request, response);
if (isTokenedServerResource()) {
boolean containsToken = containsToken(request);
if (containsToken) {
return result + 0.1f;
} else {
return result - 0.1f;
}
}
return result;
}
方法 isTokenedServerResource
检查与路由关联的服务器资源(如果有)是否为 class TokenedResource
。在这种情况下,我们查看有效载荷,看看它是否真的包含一个使用 containsToken
.
方法的令牌
这是方法 isTokenedServerResource
:
的示例内容
private boolean isTokenedServerResource() {
if (getNext() instanceof CustomFinder) {
CustomFinder finder = (CustomFinder) getNext();
if (MyServerResource1.class.isAssignableFrom(finder.getTargetClass())) {
return true;
}
}
return false;
}
这是方法 containsToken
的示例内容。它假设使用了一个JSON内容,我们使用Jackson来解析它。
private boolean containsToken(Request request) {
try {
Representation repr = request.getEntity();
String content = repr.getText();
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> jsonContent = objectMapper.readValue(
content, Map.class);
StringRepresentation sRepr = new StringRepresentation(
content, repr.getMediaType());
request.setEntity(sRepr);
if (jsonContent.get("token") != null) {
return true;
}
} catch (Exception ex) {
(...)
}
return false;
}
需要注意的一点是,我们需要在请求中重新设置请求实体(我们这里使用了一个StringRepresentation
),因为实体内容默认只能读取一次。
希望对你有帮助,
蒂埃里
我有一个 POST
请求,我想根据正文内容分配给不同的 Resources
。
如果正文包含一个非空的 token: "token":"1q2w3e4r5t"
那么我想将请求路由到 TokenedResource,
否则路由到 NonTokenResource
.
我想为它使用过滤器 (@beforeHandle
),但过滤器 returns 的唯一指示是 CONTINUE
或 STOP
...
有什么建议吗?
为此,您需要扩展 Restlet 路由。后者负责根据计算的分数确定哪个路由与特定请求匹配。
特别是路由涉及您需要覆盖的两个 class:Router
和 TemplateRoute
。路由器一负责创建模板路由。如果要提供自定义模板路由,则需要提供自定义路由。在自定义模板路由中,您可以实现自己的路由评分算法。
这是自定义路由器的实现:
public class CustomRouter extends InternalRouter {
public CustomRouter(Context context) {
super(context);
setFinderClass(CustomFinder.class);
}
protected TemplateRoute createRoute(String uriPattern,
Restlet target, int matchingMode) {
CustomTemplateRoute result = new CustomTemplateRoute(
this, uriPattern, target);
result.getTemplate().setMatchingMode(matchingMode);
result.setMatchingQuery(getDefaultMatchingQuery());
return result;
}
}
不太容易理解的是为什么我们需要使用方法 setFinderClass
指定自定义查找器。 Restlet 中的查找器负责为每个请求实例化服务器资源。默认实现(class Finder
)的问题在于您无法访问关联的 class (targetClass
)。如果你需要知道它(看起来是这样),你必须提供你自己的实现。我们稍后会重点讨论这个。
有了这个 class,这里是在应用程序中附加服务器资源的方法 class:
@Override
public Restlet createInboundRoot() {
Router router = new CustomRouter(getContext());
router.attach("/test", TokenedResource.class);
router.attach("/test", NonTokenResource.class);
return router;
}
我们必须将它们附加在同一路径上。
这里是自定义模板路由的实现:
public class CustomTemplateRoute extends TemplateRoute {
public CustomTemplateRoute(Restlet next) {
super(next);
}
public CustomTemplateRoute(Router router,
String uriTemplate, Restlet next) {
super(router, uriTemplate, next);
}
public CustomTemplateRoute(Router router,
Template template, Restlet next) {
super(router, template, next);
}
@Override
public float score(Request request, Response response) {
float result = super.score(request, response);
(...)
return result;
}
}
在方法 score
中,如果我们处于对 class TokenedResource
的标记请求的情况下,我们将增加分数,否则将减少。这允许让 Restlet select 为正确的情况提供正确的服务器资源。
在继续之前,请提供 class CustomFinder 的内容:
public class CustomFinder extends Finder {
private Class<? extends ServerResource> targetClass;
public CustomFinder() {
super();
}
public CustomFinder(Context context) {
super(context);
}
public CustomFinder(Context context,
Class<? extends ServerResource> targetClass) {
super(context, targetClass);
this.targetClass = targetClass;
}
}
这是一种实现自定义处理以计算分数的方法:
@Override
public float score(Request request, Response response) {
float result = super.score(request, response);
if (isTokenedServerResource()) {
boolean containsToken = containsToken(request);
if (containsToken) {
return result + 0.1f;
} else {
return result - 0.1f;
}
}
return result;
}
方法 isTokenedServerResource
检查与路由关联的服务器资源(如果有)是否为 class TokenedResource
。在这种情况下,我们查看有效载荷,看看它是否真的包含一个使用 containsToken
.
这是方法 isTokenedServerResource
:
private boolean isTokenedServerResource() {
if (getNext() instanceof CustomFinder) {
CustomFinder finder = (CustomFinder) getNext();
if (MyServerResource1.class.isAssignableFrom(finder.getTargetClass())) {
return true;
}
}
return false;
}
这是方法 containsToken
的示例内容。它假设使用了一个JSON内容,我们使用Jackson来解析它。
private boolean containsToken(Request request) {
try {
Representation repr = request.getEntity();
String content = repr.getText();
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> jsonContent = objectMapper.readValue(
content, Map.class);
StringRepresentation sRepr = new StringRepresentation(
content, repr.getMediaType());
request.setEntity(sRepr);
if (jsonContent.get("token") != null) {
return true;
}
} catch (Exception ex) {
(...)
}
return false;
}
需要注意的一点是,我们需要在请求中重新设置请求实体(我们这里使用了一个StringRepresentation
),因为实体内容默认只能读取一次。
希望对你有帮助, 蒂埃里