我正在尝试创建一个简单的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标头,但我不知道要添加哪一个。
答案 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请求的格式错误。