Java Socket HTTP GET请求

时间:2018-02-16 09:49:02

标签: java sockets http

我正在尝试创建一个简单的Java程序,通过使用Socket为本地托管的HTTP服务器创建HTTP请求。

这是我的代码:

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();
    }

但是当我运行它时,服务器响应'400 Bad request error'。 问题是什么?也许要添加一些HTTP标头,但我不知道要添加哪一个。

2 个答案:

答案 0 :(得分:0)

根据HTTP 1.1

  

HTTP / 1.1将序列CR LF定义为所有的行尾标记   协议元素除了entity-body [...]。

因此,您需要将所有请求以import { WebView } from 'tns-core-modules/ui/web-view'; declare var WKUserScript, WKUserScriptInjectionTime, WKUserContentController, WKWebViewConfiguration, WKWebView, CGRectZero; (<any>WebView.prototype).createNativeView = function () { const jScript = `var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'initial-scale=1.0 maximum-scale=1.0'); document.getElementsByTagName('head')[0].appendChild(meta);`; const wkUScript = WKUserScript.alloc().initWithSourceInjectionTimeForMainFrameOnly(jScript, WKUserScriptInjectionTime.AtDocumentEnd, true); const wkUController = WKUserContentController.new(); wkUController.addUserScript(wkUScript); const configuration = WKWebViewConfiguration.new(); configuration.userContentController = wkUController; configuration.preferences.setValueForKey( true, "allowFileAccessFromFileURLs" ); return new WKWebView({ frame: CGRectZero, configuration: configuration }); }; 结尾。

答案 1 :(得分:0)

您的请求存在以下几个问题:

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

要使用的换行符必须是Carriage-Return / Newline,即您应该将其更改为

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

将数据写入OutputStream时会出现下一个问题:

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

readBytes没有指定charset的调用使用系统的charset,它可能与此处所需的不同,更好地使用getBytes("8859_1")。写入流时,如果使用的字符集导致将一个字符转换为多个字节(例如,使用UTF-8作为编码),则使用header.length(),这可能与生成的字节数组的长度不同。更好地使用byteHeader.length

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

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

发送标题数据后,您应该在OutputStream上执行flush,以确保正在使用的流中没有内部缓冲区阻止数据实际发送到服务器。

in.available()仅返回可以无阻塞地从InputStream读取的字节数。它从服务器返回的数据长度。作为初学者的简单解决方案,您可以将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();

哦,独立形成自己做HTTP请求的主题:

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

这是性能和内存的噩梦,因为Java实际上是缓存内存中的所有字符串以便重用它们。因此,内部缓存会填充此连接的每个结果。 100 KB大小的响应意味着在此期间至少分配了5 GB的内存,从而导致在此过程中进行大量垃圾收集运行。

哦,关于服务器的响应:这很可能来自使用的无效换行符。服务器将整个标题包括空行作为单行,并且由于HTTP / 1.1之后的附加数据而抱怨GET请求的格式错误。