简体   繁体   English

Java Socket HTTP GET请求

[英]Java Socket HTTP GET request

I'm trying to create a simple Java program that create an HTTP request to a HTTP server hosted locally, by using Socket. 我正在尝试创建一个简单的Java程序,该程序通过使用Socket向本地托管的HTTP服务器创建HTTP请求。

This is my code: 这是我的代码:

try
    {
        //Create Connection
        Socket s = new Socket("localhost",80);
        System.out.println("[CONNECTED]");
        DataOutputStream out = new DataOutputStream(s.getOutputStream());
        DataInputStream in   = new DataInputStream(s.getInputStream());


        String header = "GET / HTTP/1.1\n"
                +"Host:localhost\n\n";
        byte[] byteHeader = header.getBytes();
        out.write(byteHeader,0,header.length());

        String res = "";
        /////////////READ PROCESS/////////////
        byte[] buf = new byte[in.available()];
        in.readFully(buf);
        System.out.println("\t[READ PROCESS]");
        System.out.println("\t\tbuff length->"+buf.length);
        for(byte b : buf)
        {
            res += (char) b;
        }
        System.out.println("\t[/READ PROCESS]");
        /////////////END READ PROCESS/////////////

        System.out.println("[RES]");
        System.out.println(res);
        System.out.println("[CONN CLOSE]");

        in.close();
        out.close();
        s.close();


    }catch(Exception e)
    {
        e.printStackTrace();
    }

But by when I run it the Server reponse with a '400 Bad request error'. 但是,当我运行它时,服务器将响应“ 400错误的请求错误”。 What is the problem? 问题是什么? Maybe some HTTP headers to add but I don't know which one to add. 也许要添加一些HTTP标头,但我不知道要添加哪个标头。

According to HTTP 1.1 : 根据HTTP 1.1

HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all protocol elements except the entity-body [...]. HTTP / 1.1将序列CR LF定义为实体实体以外所有协议元素的行尾标记。

So, you'll need all of your request to be ending with \\r\\n . 因此,您需要所有请求以\\r\\n结尾。

There are a couple of issues with your request: 您的请求有两个问题:

String header = "GET / HTTP/1.1\n"
             + "Host:localhost\n\n";

The line break to be used must be Carriage-Return/Newline, ie you should change that to 要使用的换行符必须是回车符/换行符,即您应该将其更改为

String header = "GET / HTTP/1.1\r\n"
             + "Host:localhost\r\n\r\n";

Next problem comes when you write the data to the OutputStream: 将数据写入OutputStream时出现下一个问题:

    byte[] byteHeader = header.getBytes();
    out.write(byteHeader,0,header.length());

The call of readBytes without the specification of a charset uses the system's charset which might be a different than the one that is needed here, better use getBytes("8859_1") . 在不指定字符集的情况下调用readBytes使用系统的字符集,该字符集可能与此处所需的字符集有所不同,最好使用getBytes("8859_1") When writing to the stream, you use header.length() which might be different from the length of the resulting byte-array if the charset being used leads to the conversion of one character into multiple bytes (eg with UTF-8 as encoding). 写入流时,如果使用的字符集导致将一个字符转换为多个字节(例如,使用UTF-8编码),则可以使用header.length() ,它可能与所得字节数组的长度不同。 。 Better use byteHeader.length . 最好使用byteHeader.length

    out.write(byteHeader,0,header.length());

    String res = "";
    /////////////READ PROCESS/////////////
    byte[] buf = new byte[in.available()];

After sending the header data you should do a flush on the OutputStream to make sure that no internal buffer in the streams being used prevents the data to actually be sent to the server. 发送标头数据之后,应该对OutputStream进行flush ,以确保所使用的流中没有内部缓冲区阻止将数据实际发送到服务器。

in.available() only returns the number of bytes you can read from the InputStream without blocking. in.available()仅返回您可以从InputStream读取而没有阻塞的字节数。 It's not the length of the data being returned from the server. 不是从服务器返回的数据的长度。 As a simple solution for starters, you can add Connection: close\\r\\n to your header data and simply read the data you're receiving from the server until it closes the connection: 作为入门的简单解决方案,您可以将Connection: close\\r\\n到标头数据中,并简单地读取从服务器接收的数据,直到它关闭连接为止:

StringBuffer sb = new StringBuffer();
byte[] buf = new byte[4096];
int read;
while ((read = in.read(buf)) != -1) {
    sb.append(new String(buf, 0, read, "8859_1"));
}
String res = sb.toString();

Oh and independent form the topic of doing an HTTP request by your own: 哦,独立地形成了由您自己执行HTTP请求的主题:

    String res = "";
    for(byte b : buf)
    {
        res += (char) b;
    }

This is a performance and memory nightmare because Java is actually caching all strings in memory in order to reuse them. 这是性能和内存的噩梦,因为Java实际上正在缓存内存中的所有字符串以重用它们。 So the internal cache gets filled with each result of this concatenation. 因此,内部缓存被此串联的每个结果填充。 A response of 100 KB size would mean that at least 5 GB of memory are allocated during that time leading to a lot of garbage collection runs in the process. 100 KB大小的响应将意味着在此期间至少分配了5 GB的内存,导致该过程中运行大量垃圾回收。

Oh, and about the response of the server: This most likely comes from the invalid line breaks being used. 哦,关于服务器的响应:这很可能来自使用无效的换行符。 The server will regard the whole header including the empty line as a single line and complains about the wrong format of the GET-request due to additional data after the HTTP/1.1. 服务器会将包括空行在内的整个标头视为一行,并且由于HTTP / 1.1之后的附加数据而抱怨GET请求的格式错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM