java - 分块传输编码时如何使用 HttpsUrlconnection 读取响应

标签 java http servlets urlconnection httpsurlconnection

我正在编写一个 servlet,它在内部使用 HttpsUrlConnection 来调用另一个 Url。从 servlet,我必须返回从 HttpsUrlConnection 调用收到的相同响应和相同响应 header 。

为此,我使用 getHeaderFields() 读取所有 header :将返回的 header 复制到我的 servlet 的 Httpservletresponse 对象。

此外,之后我尝试使用 connection.getErrorStream() 读取响应(这主要发生在服务器返回状态 > 400 时),这就是我使用 getErrorStream 的原因。然后我读取字节并将字节复制到我的 servlet 的 HttpServletResponse 输出流。

现在这在某些情况下工作正常。

但是当我使用连接调用的服务器返回带有分块传输编码的响应时,当我调用我的 servlet API 时,如果我将响应和响应 header 复制到 Httpservlet 响应,它会返回无效 block 编码的错误。

在这种情况下,在日志中我看到当我使用 getHeaderFields 读取 header 时,我看到的第一个 header 是 Transfer encoding chunked,然后下一个 header 名称为 null,它的值为 HTTP 1/1。

另外,我看到的回复也不妥。

在这种情况下,如何从 httpsurl 连接读取响应 header 和响应主体,并从我的 servlet 正确返回它?

最佳答案

我在分块编码方面遇到了类似的问题。与您不同的是,我的 servlet 在内部使用 HTTP 而不是 HTTPS。

我也使用一种方法来复制 header 字段。但我提供了一个由 servlet 容器管理的 header 列表,因此我不创建、复制或编辑它们:

 private static final Set forbiddenCopyHeaders = new HashSet<>(Arrays.asList(new String[]{
            "connection"
            , "transfer-encoding"
            , "content-length"
            , "via"
            , "x-forwarded-for"
            , "x-forwarded-host"
            , "x-forwarded-server"
    }));

这些是我用来复制响应头的方法:

  private void copyResponseHeaders(CloseableHttpResponse internResponse, HttpServletResponse response)
    {
        Header[] headers = internResponse.getAllHeaders();
        Header[] connHeaders = internResponse.getHeaders("connection");
        StringBuilder connectionValue = new StringBuilder();

        for (Header connHeader : connHeaders)
        {
            connectionValue.append(connHeader.getValue()).append(", ");
        }

        for (Header header : headers)
        {
            String headerName = header.getName();

            boolean copyAllowed = !forbiddenCopyHeaders.contains(headerName.toLowerCase())
                    && !StringUtils.containsIgnoreCase(connectionValue.toString(), headerName);

            if (copyAllowed)
            {
                if (response.containsHeader(headerName))
                {
                    response.addHeader(headerName, header.getValue());
                }
                else
                {
                    response.setHeader(headerName, header.getValue());
                }
            }
        }

        setViaHeader(internResponse, response);
    }

方法 setViaHeader():

private void setViaHeader(CloseableHttpResponse response, HttpServletResponse customerResponse)
    {
        String serverHostName = "companyServer";
        try
        {
            serverHostName = InetAddress.getLocalHost().getHostName();
        }
        catch (UnknownHostException e)
        {
            logger.error("für den VIA-Header kann der Hostname nicht ermittelt werden", e);
            System.err.println("für den VIA-Header kann der Hostname nicht ermittelt werden: " +
                    ExceptionUtils.getStackTrace(e));
        }

        Header[] originalViaHeaders = response.getHeaders("via");
        StringBuilder via = new StringBuilder("");
        if ((originalViaHeaders != null) && (originalViaHeaders.length > 0))
        {
            for (Header viaHeader : originalViaHeaders)
            {
                via.append(viaHeader.getValue()).append(", ");
            }
        }
        via.append(response.getStatusLine().getProtocolVersion().toString()).append(" ").append(serverHostName);

        customerResponse.setHeader("via", via.toString());
    }

关于java - 分块传输编码时如何使用 HttpsUrlconnection 读取响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35677425/

相关文章:

java - 表单加载但进程不会停止

apache - 在事件链中调用 servlet

Java 分类 - 什么是最好的方法

java - HashMap 实际元素的索引

Java 单线程 RMI 或替代方案

angularjs - $http 拦截器导致无限循环

java - 无法从 Servlet 连接数据库

java - 通过 jni 将相同的 Android surfaceview 传递给 C++ 代码会导致不同的值

c# - 检查 iFrame 是否由允许的域托管

php - 如何在 PHP 中使用 file_get_contents 获取图像的 MIME 类型