如何通过套接字读取HTTP响应?

11

我正在尝试在安卓设备上创建http代理服务器。当我试图从HTTP服务器(example1.com)读取响应时(example1.com在头部包含 content-length),如果HTTP服务器包含content-length,则我会读取来自content-length的字节,否则我会读取响应的全部字节。

byte[] bytes = IOUtils.toByteArray(inFromServer);

问题在于,当响应包含content-length时,响应的读取速度很快。 如果响应不包含content-length,则响应读取较慢。

这是我的代码:

DataInputStream in = new DataInputStream(inFromServer);
        //BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String line = "";
        String str = "";
        Integer len = 0;
        while(true) {
            line = in.readLine();
            if  (line.indexOf("Content-Length") != -1)
            {
                len = Integer.parseInt( line.split("\\D+")[1] );
                //System.out.println("LINEE="+len);
            }

            out.println(line);
            str = str + line + '\n';
            if(line.isEmpty())  break;
        }
        int i = Integer.valueOf(len);
        String body= "";
        System.out.println("i="+i);
        if (i>0) {
            byte[] buf = new byte[i];
            in.readFully(buf);
            out.write(buf);
            for (byte b:buf) {
                body = body + (char)b;
            }

        }else{

            byte[] bytes = IOUtils.toByteArray(inFromServer);
            out.write(bytes);
        }

输出 - 将数据流发送到浏览器


当读取所有字节时,阅读正文大约需要5分钟。 - Petr
让我们在聊天室中继续这个讨论 - Petr
inFromServer是什么? - greenapps
2
如果响应中不包含Content-Length,则很可能使用分块编码,你需要相应处理。只有当没有分块编码和Content-Length,并且状态码表示存在响应体(即不是304),且请求方法表明存在响应体(即不是HEAD)时,才应该一直读取到连接结束。如果想学习协议的工作原理,我建议你实际研究一下标准文档 - Steffen Ullrich
一旦您声明了DataInputStream并从中读取数据,您应该始终从中读取数据,而不是回退到inFromServer。 - greenapps
显示剩余5条评论
2个回答

7
首先,您需要了解HTTP协议及其工作原理。
每个HTTP请求包括以下内容:
- 请求行 - 请求头 - 空行 - 请求体
每个HTTP响应包括以下内容:
- 状态行 - 响应头 - 空行 - 响应体
我们可以从HTTP服务器读取InputStream,并将我们从InputStream读取的每一行以“/r/n”结尾分割。
以下是您的代码:
while(true) {
    **line = in.readLine();**
    if  (line.indexOf("Content-Length") != -1)
    {
        len = Integer.parseInt( line.split("\\D+")[1] );
            //System.out.println("LINEE="+len);
        }

        out.println(line);
        str = str + line + '\n';
        if(line.isEmpty())  break;
    }
}

in.readLine()方法返回不以'/r/n'结尾的每一行,它返回以'/r'或'/n'结尾的行。在此处可能会从输入流中阻塞读取。

这里有一个IOStreamUtils工具类可以读取以'/r/n'结尾的行。

https://github.com/mayubao/KuaiChuan/blob/master/app/src/main/java/io/github/mayubao/kuaichuan/micro_server/IOStreamUtils.java


7
请尝试以下代码:

// Get server response
int responseCode = connection.getResponseCode();
if (responseCode == 200) {
    BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    String line;
    StringBuilder builder = new StringBuilder();
    while ((line = reader.readLine()) != null) {
        builder.append(line);
    }
    String response = builder.toString()
    // Handle response...
}

上述代码中的添加部分:代码应该处理异常。在大多数情况下,如果响应码为200,则响应流可能为空。 - dev_kj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接