如何解决这个Java程序如何工作
这里是使用Java执行HTTP GET请求的程序,它获取HTML文档并将其保存在文本文件中。但是问题是我无法理解这段代码的某些部分。
import java.io.*;
import java.net.*;
public class HTTP {
public static void main(String[] args) {
try {
FileOutputStream to_file = new FileOutputStream("f:\\temp.txt");
URL url = new
URL("http://www.dailygames.com/3dgames.html");
String protocol = url.getProtocol();
String host = url.getHost();
int port = url.getPort();
if (port == -1) {
port = 80;
}
String filename = url.getFile();
System.out.println(filename);
Socket socket = new Socket(host,port);
InputStream from_server = socket.getInputStream();
PrintWriter to_server = new PrintWriter(socket.getoutputStream());
to_server.print("GET" + filename + "\n\n");
to_server.flush();
byte[] buffer = new byte[4096];
int byte_read;
while ((byte_read = from_server.read(buffer)) != -1) {
to_file.write(buffer,byte_read);
System.out.print((char) byte_read);
}
socket.close();
to_file.close();
} catch (Exception e) {
e.printstacktrace();
}
}
}
为什么我们应该在这里使用PrintWriter
PrintWriter to_server = new PrintWriter(socket.getoutputStream());
to_server.print("GET" + filename +"\n\n");
print()函数的用途是什么。当我运行该程序时,我创建了一个文本文件,但给出的错误响应为400,而不是200 OK。如何理解此代码以使其正常工作
HTTP/1.1 400 Bad Request
Date: Fri,23 Oct 2020 08:27:26 GMT
Server: Apache
Content-Length: 226
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server Could not understand.<br />
</p>
</body></html>
该程序以哪一行代码将请求发送到服务器。
解决方法
要回答您的问题,
为什么我们应该在这里使用PrintWriter
您还可以在此处使用 BufferedWriter 。但是 PrintWriter 提供了 println()方法来在不同平台上写入换行符,并且 BufferedWriter 需要显示对newLine方法的调用。即 newline()可用于换行。 另外,PrintWriter构造函数可以指定参数以实现自动刷新缓存。
您可以参考此链接https://www.programmersought.com/article/9176292993/,详细说明使用套接字API时两者之间的区别
print()函数的用途是什么
在此程序中,to_server.print("GET" + filename +"\n\n");
print()用于发送标头,或换句话说,将请求字符串打印到输出流
但是,您需要在此处进行一些更改:
- 就像@Fred在评论中建议的那样,GET和url之间必须有一个空格
- 将协议版本添加到您的请求标头中
- 使用println()而不是print()将条目打印到单独的行中。
- 将域名添加到请求行
例如,
to_server.println("GET " + filename + " HTTP/1.1");
to_server.println("Host: "+host+"\r\n");
该程序以哪一行代码将请求发送到服务器。
总的来说,您的程序按以下步骤工作,并且对该问题的答案位于步骤2和#3(请参见下面的代码中的注释)
- 创建与主机和端口的套接字连接,即http://www.dailygames.com和80
- 通过路径和协议版本(即GET /3dgames.html HTTP / 1.1)将HTTP数据包发送到包含方法,资源的outputstream中
- 正确阅读和解释回复
这是您如何获得所需回复的方法:
import java.io.*;
import java.net.*;
public class HTTP {
public static void main(String[] args) {
try {
FileOutputStream to_file = new FileOutputStream("f:\\temp.txt");
URL url = new URL("http://www.dailygames.com/3dgames.html");
String host = url.getHost();
int port = url.getPort();
if (port == -1) {
port = 80;
}
String filename = url.getFile();
System.out.println(filename);
//Create Connection
//Open socket to a specific host and port
Socket socket = new Socket(host,port);
//Get input and output streams for the socket
InputStream from_server = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
// Get response OR Instantiates a new PrintWriter passing in the sockets output stream
PrintWriter to_server = new PrintWriter(outputStream);
// Send headers OR Prints the request string to the output stream
to_server.println("GET " + filename + " HTTP/1.1"); // This is a message sent to the server
to_server.println("Host: " + host); // As you can see,the domain name is passed to the program as an argument. After connected to the server,it sends the domain name,and reads the response from the server.
to_server.println("");
to_server.flush();
byte[] buffer = new byte[4096];
int byte_read;
//Reads & Prints each line of the response OR Reads HTTP response
while ((byte_read = from_server.read(buffer)) != -1) {
// Print server's response
to_file.write(buffer,byte_read);
System.out.print((char) byte_read);
}
socket.close();
to_file.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
,
尝试一下
import java.io.*;
import java.net.*;
public class HTTP {
public static void main(String[] args) {
try {
URL url = new URL("http://www.dailygames.com/3dgames.html");
String host = url.getHost();
int port = url.getPort();
if (port == -1) {
port = 80;
}
try (
Socket socket = new Socket(host,port);
BufferedReader serverReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter serverWriter = new PrintWriter(socket.getOutputStream(),true);
Writer destinationFile = new PrintWriter(new FileOutputStream("f:\\temp.txt"),true)
) {
System.out.println("Connection to [" + host + "] status [" + socket.isConnected() + "]");
final String request = "GET " + url.getFile() + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n" +
"\r\n";
System.out.println("REQ: " + request);
serverWriter.print(request);
serverWriter.flush();
final StringBuilder sb = new StringBuilder();
String line;
// Store response to file
while ((line = serverReader.readLine()) != null) {
sb.append(line);
}
destinationFile.write(sb.toString());
}
System.out.println("Completed");
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
编辑: 我已经通过添加try-with-resources进行了一些常规的清理工作,因此不会打开任何资源,否则应该在finally语句中进行关闭。
为方便起见,我将流资源包装在高级API读写器中。
原始代码的主要问题是:
- 缺少“主机:foo”。
- 在末尾添加最后一个换行符。
编辑后,发送到服务器的查询将是:
GET /3dgames.html HTTP/1.1 \r\n
Host: http://www.dailygames.com \r\n
Connection: close \r\n
\r\n
我还按照HTTP规范中的指定明确设置了\ r \ n。 println中的行结尾使用系统属性line.separator,该属性可能不是\ r \ n
更正代码后,它可以工作。但是除了不错的练习外,我还会为HTTP请求而不是Socket(HttpClient / OKHttp / etc)选择更高级别的API
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。