0

我们有两个 RESTful API——一个是内部的,另一个是公共的,这两个由不同的 jar 实现。公共 API 封装了内部 API,执行以下步骤:

  1. 做一些工作
  2. 调用内部API
  3. 做一些工作
  4. 将响应返回给用户

可能会发生(尽管不一定)这两个 jar 在同一个 Java 进程中运行。

我们使用带有 JAX-RS 扩展的 Restlet。

这是一个简单的公共 API 实现示例,它只是转发到内部 API:

@PUT
@Path("abc")
public MyResult method1(@Context UriInfo uriInfo, InputStream body) throws Exception {
  String url = uriInfo.getAbsolutePath().toString().replace("/api/", "/internalapi/");
  RestletClientResponse<MyResult> reply = WebClient.put(url, body, MyResult.class);
  RestletUtils.addResponseHeaders(reply.responseHeaders);
  return reply.returnObject;
}

在哪里WebClient.put

public class WebClient {
  public static <T> RestletClientResponse<T> put(String url, Object body, Class<T> returnType) throws Exception {
    Response restletResponse = Response.getCurrent();
    ClientResource resource = new ClientResource(url);
    Representation reply = null;
    try {
      Client timeoutClient = new Client(Protocol.HTTP);
      timeoutClient.setConnectTimeout(30000);
      resource.setNext(timeoutClient);

      reply = resource.put(body, MediaType.APPLICATION_JSON);
      T result = new JacksonConverter().toObject(new JacksonRepresentation<T>(reply, returnType), returnType, resource);

      Status status = resource.getStatus();
      return new RestletClientResponse<T>(result, (Form)resource.getResponseAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS), status);
    } finally {
      if (reply != null) {
        reply.release();
      }
      resource.release();
      Response.setCurrent(restletResponse);
    }
  }
}

并且RestletClientResponse<T>是:

public class RestletClientResponse<T> {
  public T returnObject = null;
  public Form responseHeaders = null;
  public Status status = null;

  public RestletClientResponse(T returnObject, Form responseHeaders, Status status) {
    this.returnObject = returnObject;
    this.responseHeaders = responseHeaders;
    this.status = status;
  }
}

并且RestletUtils.addResponseHeaders是:

public class RestletUtils {
  public static void addResponseHeader(String key, Object value) {
    Form responseHeaders = (Form)org.restlet.Response.getCurrent().getAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS);
    if (responseHeaders == null) {
      responseHeaders = new Form();
      org.restlet.Response.getCurrent().getAttributes().put(HeaderConstants.ATTRIBUTE_HEADERS, responseHeaders);
    }
    responseHeaders.add(key, value.toString());
  }

  public static void addResponseHeaders(Form responseHeaders) {
    for (String headerKey : responseHeaders.getNames()) {
      RestletUtils.addResponseHeader(headerKey, responseHeaders.getValues(headerKey));
    }
  }
}

问题是如果两个 jars 在同一个 Java 进程中运行,那么从内部 API 抛出的异常不会路由到内部 API 的 JAX-RS 异常映射器 - 异常向上传播到公共 API 并被转换为内部服务器错误 (500)。

这意味着我做错了。所以,我的问题是如何从公共 API 实现中调用内部 RESTful API,因为客户端和服务器都可以在同一个 Java 进程中运行。

当然,还有其他问题,但我有一种感觉,修复我刚才描述的问题也会解决其他问题。

4

1 回答 1

0

这个问题与内部和公共 JAR 都在同一个 JVM 中这一事实无关。它们完全由WebResource.put()方法分开,这会创建一个新的 HTTP 会话。因此,内部 API 中的异常不会传播到公共 API。

公共 API 中的内部服务器错误是由后处理机制引起的,该机制解释了内部 API 的输出并由于某种原因而崩溃。不要责怪内部 API,它是完全隔离的,不会造成任何麻烦(即使它在同一个 JVM 中)。

于 2013-03-09T08:09:33.387 回答