Java Jersey ClientResponse 从 getClientResponseStatus 返回错误状态

标签 java junit jersey jersey-client

我觉得我错过了一些东西。我有一个过滤器,可以打印出服务器返回的信息,并且我报告我正在返回正确的响应(403)。我编写了一个 JUnit 测试来验证这个逻辑,很多时候我报告 200 而不是 403。奇怪的是我的服务器日志仍然显示我发送了 403。Jersey 1.17 中是否存在一些我不知道的已知错误而且我需要升级才能解决?我现在确实无法升级,所以我希望我的逻辑存在一些错误。这是我的测试用例。

@Test
public void testIdsOwnedBySomeoneElse()
{
    final Login user1Cred = Logins.getInstance().getLogin(Logins.LoginType.User1);
    final Login user2Cred = Logins.getInstance().getLogin(Logins.LoginType.User2);
    final ServiceEndpointAuthenticated authUser1 = LoginHelper.Login(user1Cred);
    final ServiceEndpointAuthenticated authUser2 = LoginHelper.Login(user2Cred);

    // Create generic entry owned by user 1
    BigInteger user1Id = null;
    {
        final Object payload = endpoint.CreateEntity(authUser1.getUserId());
        final ClientResponse response = endpoint.Post(authUser1, payload);
        assertTrue(Status.OK == response.getClientResponseStatus());
        final byte[] data = Utilities.getBytes(response.getEntityInputStream());
        user1Id = endpoint.getEntityId(data);
    }

    // Using User2, try to use that id from user1!
    {
        // test 1
        final MyEndpointWrapper endpoint = new MyEndpointWrapper(user1Id, validId);
        final Object payload = endpoint.CreateEntity(authUser2.getUserId());
        final ClientResponse response = endpoint.Post(authUser2, payload);
        final Status status = response.getClientResponseStatus();
        System.out.println("Returned status = " + status);
        if (status != Status.FORBIDDEN)
        {
            byte[] data = Utilities.getBytes(response.getEntityInputStream());
            String toString = null;
            try
            {
                toString = new String(data, "UTF-8");
            }
            catch (UnsupportedEncodingException e)
            {
            }
            System.out.println("data: " + toString);
        }
        assertEquals("Status " + status + " is not forbidden!", Status.FORBIDDEN, status);
    }

    {
        // test 2
        final MyEndpointWrapper endpoint = new MyEndpointWrapper(validId, user1Id);
        final Object payload = endpoint.CreateEntity(authUser2.getUserId());
        final ClientResponse response = endpoint.Post(authUser2, payload);
        final Status status = response.getClientResponseStatus();
        System.out.println("Returned status = " + status);
        if (status != Status.FORBIDDEN)
        {
            int i = 9;
        }
        assertEquals("Status " + status + " is not forbidden!", Status.FORBIDDEN, status);
    }

    // Go ahead and delete this data for cleanup
    assertTrue(Status.OK == endpoint.Delete(authUser1, user1Id).getClientResponseStatus());
}

我的通用代码首先登录我们的服务器以获取凭据。这些凭据“附加”到 WebResource,并且当我构建请求时它会自动附加正确的 header 。我首先创建一个实体,发布它,并存储返回的 id 以供其他用户使用。我创建了另一个引用该违规 ID 的端点包装器,并尝试使用该 ID 进行发布。服务器日志:

INFO: RESPONSE: 403 http://myendpoint MediaType:(application/json) Payload: 232 MyErrorMessage

我什至可以打印此消息(如上所示)!我不明白的部分是 getClientResponseStatus 返回给我 OK。为什么?

我的邮政编码如下:

@Override
public ClientResponse Post(ServiceEndpointAuthenticated endpoint, Object entity)
{
    MyUploadData uploadData = (MyUploadData)entity;
    return endpoint.getResourceBuilder("/myendpoint")
            .accept(MediaTypeExt.APPLICATION_JSON)
            .type(MediaTypeExt.APPLICATION_JSON)
            .post(ClientResponse.class, gson.toJson(uploadData));
}

[更新] 我运行了wire capture,实际上确实看到了 200 个被发回!这似乎确实是 Jersey Server 内部的东西。这是我所看到的:

When working:
Request: 1099   17.021219000    127.0.0.1   127.0.0.1   HTTP    2214    POST /myEndpoint HTTP/1.1  (application/json)
Response: 1153  17.042535000    127.0.0.1   127.0.0.1   HTTP    628 HTTP/1.1 400 Bad Request  (application/json)

When not working:
Request: 1161   17.044313000    127.0.0.1   127.0.0.1   HTTP    250 POST /myEndpoint HTTP/1.1  (application/json)
Response: 1217  17.066059000    127.0.0.1   127.0.0.1   HTTP    412 HTTP/1.1 200 OK 

当它工作时,我会在响应中看到正常的 header (例如:Access-Control-*、Pragma no cache 等)。当它不起作用时,我看不到任何 header ,但我确实看到“Transfer-Encoding:分块”,我的响应是我的错误消息,但我的响应代码是 200。在我之前,我在服务器中添加了显式 Trace 语句发送了我的回复,以确保我发送了正确的状态,而且我确实是。

我同意允许分块传输,但我不太同意丢失我想要的 http 响应。

最佳答案

万一其他人遇到类似的事情。经过一番摸索,我终于发现了问题所在。我们的一些端点有心跳。某些端点可能需要比预期更长的时间。为了确保客户端不会过早断开连接,我们有一个附加到 ServletOutputStream 的组件。这会向客户端发送一个空格以保持连接处于 Activity 状态。

当抛出错误时(由我们的新异常重新映射器捕获),此保持 Activity 组件未正确关闭。这导致 Jersey 切换到分块模式。确保保持 Activity 组件正确关闭可以解决问题。

关于Java Jersey ClientResponse 从 getClientResponseStatus 返回错误状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26261212/

相关文章:

使用 jersey 的 REST 服务输出中的 java.util.Map

java - 如何在 ShrinkWrap 容器中使用 log4j2?

java - 在 Java Web 服务中引发用户定义的异常时出现错误

java - 无法使用 spring boot jpa 创建新表

java - 使用 VSCode 并获取 NoClassDefFoundError

升级到 Java 8 和构建工具版本 25 后 Android 测试用例失败

java - JUnit 终止子线程

java - 如何检索 Jersey ContainerRequest 属性?

java - 我希望根据 Excel 中声明的运行模式运行测试用例

java - Jersey 可以生成 List<T> 但不能 Response.ok(List<T>).build()?