球衣 2.0 内容长度未设置

2022-09-03 14:38:01

我正在尝试发布到需要使用以下代码设置内容长度标头的 Web 服务:

// EDIT: added apache connector code
ClientConfig clientConfig = new ClientConfig();
ApacheConnector apache = new ApacheConnector(clientConfig);

// setup client to log requests and responses and their entities
client.register(new LoggingFilter(Logger.getLogger("com.example.app"), true));

Part part = new Part("123");
WebTarget target = client.target("https://api.thing.com/v1.0/thing/{thingId}");
Response jsonResponse = target.resolveTemplate("thingId", "abcdefg")
                .request(MediaType.APPLICATION_JSON)
                .header(HttpHeaders.AUTHORIZATION, "anauthcodehere")
                .post(Entity.json(part));

发行说明 https://java.net/jira/browse/JERSEY-1617 和泽西岛 2.0 文档 https://jersey.java.net/documentation/latest/message-body-workers.html 这意味着内容长度是自动设置的。但是,我从服务器收到一个411响应代码,指示请求中不存在Content-Length。

有谁知道获取内容长度标头集的最佳方法吗?

我已通过设置记录器验证了请求中未生成 Content-Length 标头。

谢谢。


答案 1

我使用 Jersey Client 2.2 和 Netcat 进行了快速测试,它向我显示 Jersey 正在发送 Content-Length 标头,即使 LoggingFilter 没有报告它。

为了做这个测试,我首先在一个shell中运行netcat。

nc -l 8090

然后,我在另一个 shell 中执行了以下 Jersey 代码。

Response response = ClientBuilder.newClient()
    .register(new LoggingFilter(Logger.getLogger("com.example.app"), true))
    .target("http://localhost:8090/test")
    .request()
    .post(Entity.json(IOUtils.toInputStream("{key:\"value\"}")));

运行此代码后,将记录以下行。

INFO: 1 * LoggingFilter - Request received on thread main
1 > POST http://localhost:8090/test
1 > Content-Type: application/json
{key:"value"}

但是,netcat 会在消息中报告更多标头。

POST /test HTTP/1.1
Content-Type: application/json
User-Agent: Jersey/2.0 (HttpUrlConnection 1.7.0_17)
Host: localhost:8090
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Length: 13

{key:"value"}

我用Java6和Java7在OSX上运行了这个测试,结果相同。我也在泽西岛2.0中进行了测试,结果类似。


答案 2

在查看ApacheConnector类的源代码后,我看到了问题。当客户端请求转换为 HttpUriRequest 时,将调用一个返回 Http 实体的私有方法。不幸的是,这将返回一个 HttpEntity,其始终返回 -1。getHttpEntity()getContentLength()

当Apache http客户端创建请求时,它将查询HttpEntity对象的长度,并且由于它返回-1,因此不会设置标头。Content-Length

我通过创建一个新的连接器来解决我的问题,该连接器是ApacheConnector源代码的副本,但具有不同的.我将原始实体读取到一个字节数组中,然后用.当Apache Http客户端创建请求时,它将咨询实体,并将使用正确的内容长度进行响应,从而允许设置标头。getHttpEntity()ClientRequestByteArrayEntityByteArrayEntityContent-Length

以下是相关代码:

private HttpEntity getHttpEntity(final ClientRequest clientRequest) {
    final Object entity = clientRequest.getEntity();

    if (entity == null) {
        return null;
    }

    byte[] content = getEntityContent(clientRequest);

    return new ByteArrayEntity(content);
}


private byte[] getEntityContent(final ClientRequest clientRequest) {

   // buffer into which entity will be serialized
   final ByteArrayOutputStream baos = new ByteArrayOutputStream();

   // set up a mock output stream to capture the output
   clientRequest.setStreamProvider(new OutboundMessageContext.StreamProvider() {

        @Override
        public OutputStream getOutputStream(int contentLength) throws IOException {
            return baos;
        }
    });

    try {
        clientRequest.writeEntity();
    } 
    catch (IOException e) {
        LOGGER.log(Level.SEVERE, null, e);
        // re-throw new exception
        throw new ProcessingException(e);
    }

    return baos.toByteArray();
}

警告:我的问题空间受到限制,并且仅包含作为请求一部分的小实体正文。上面提出的这种方法对于大型实体体(如图像)可能会有问题,因此我不认为这是所有人的通用解决方案。


推荐