Java通过Socket请求Host URL遇400错误,如何实现目标打印与文件写入?
问题
我尝试用Java代码从gaia.cs.umass.edu获取/wireshark-labs/INTRO-wireshark-file1.html的内容,并写入/Users/brichards/message.html,但运行时返回HTTP 400错误,既无法输出指定的两行提示信息,也没正确写入目标文件。以下是我的代码、期望输出和实际错误返回:
我的代码
public static void SocketandURL(String[] args) throws Exception { String host = args[0]; // Build and send a GET request packet. The packet is a String, // and therefore needs to be converted to a sequence of bytes before it // can be sent. There's a getBytes() method in the String class to do that. // The \r and \n characters are CR and LF. The first pair ends the GET line, // the second pair ends the "blank line" marking the end of the packet. // Any header info could have to be included before that blank line. String packet = "GET /wireshark-labs/INTRO-wireshark-file1.html HTTP/1.1\r\n\r\n"; packet = "Host: " + host + packet; System.out.println("Sending packet to " + host); try { // Read the resulting data and write it to our output file. We intentionally // use a DataInputStream rather than an InputStreamReader to get the data from // the socket, since we want to allow for reading binary data files like .jpgs, // but that means we need to convert it to a character string if we ever want // to print it out. This code uses a special constructor in the String class // to do that. Note that this code assumes the entire response can be retrieved // in one call to read(). You may NOT make that assumption in your finished // program. //Get DataInputStream of Array theSocket = new Socket(host, 80); // Port 80 is HTTP byte[] buf = new byte[BUFFER_SIZE];//New byte array outgoing = theSocket.getOutputStream(); incoming = new DataInputStream(theSocket.getInputStream()); outgoing.write(packet.getBytes()); int numBytes = incoming.read(buf); String filename = "textfile.txt"; File theFile = new File(filename); if (args.length > 0) { filename = args[0]; } if (theFile.exists()) { System.out.println("It already exists. Contents will be overwritten"); } else { System.out.println("Creating new file: " + theFile.getAbsolutePath()); FileMake(args); } FileOutputStream writer = new FileOutputStream(theFile); String filePath = "/Users/bakya/Downloads/HW2/textfile.txt"; writer.write(filePath.getBytes()); writer.close(); while (numBytes > 0) { System.out.println("Got: " + (new String(buf, 0, numBytes, "UTF-8"))); host += args[0]; numBytes = incoming.read(buf); } theSocket.close(); } catch (Exception e) { System.out.println("ERR: Invalid File"); } }
期望输出
Grabbing /wireshark-labs/INTRO-wireshark-file1.html from gaia.cs.umass.edu Writing data to /Users/brichards/message.html
实际错误输出
Sending packet to gaia.cs.umass.edu It already exists. Contents will be overwritten Got: HTTP/1.1 400 Bad Request Date: Mon, 25 Sep 2023 00:46:07 GMT Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.4.33 mod_perl/2.0.11 Perl/v5.16.3 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>
解决方案
1. 修复HTTP请求格式错误(400错误的核心原因)
HTTP/1.1要求Host头必须单独以\r\n结尾,你当前的拼接方式直接把Host和GET请求行连在一起,导致请求格式非法。正确的请求构造方式:
String packet = "GET /wireshark-labs/INTRO-wireshark-file1.html HTTP/1.1\r\n" + "Host: " + host + "\r\n\r\n";
2. 修正输出文件逻辑
- 不要把
args[0](主机名)当作文件名,直接指定目标路径/Users/brichards/message.html,或者通过args[1]传递输出路径 - 代码中错误地将文件路径字符串写入文件,应改为写入从Socket读取的响应内容
- 调整文件流关闭时机,写完所有数据后再关闭
3. 添加指定的提示信息
在发送请求前输出要求的两行提示:
System.out.println("Grabbing /wireshark-labs/INTRO-wireshark-file1.html from " + host); System.out.println("Writing data to " + outputFilePath);
4. 修复循环读取逻辑
- 删除无意义的
host += args[0];代码,避免主机名被重复拼接 - 确保循环中持续读取Socket数据并写入文件,而非仅打印
修复后的完整代码
import java.io.DataInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.net.Socket; public class HttpFetcher { private static final int BUFFER_SIZE = 4096; private static Socket theSocket; private static OutputStream outgoing; private static DataInputStream incoming; public static void SocketandURL(String[] args) throws Exception { if (args.length < 2) { System.err.println("使用方式: java HttpFetcher <主机名> <输出文件路径>"); return; } String host = args[0]; String outputFilePath = args[1]; // 构造合法的HTTP请求 String packet = "GET /wireshark-labs/INTRO-wireshark-file1.html HTTP/1.1\r\n" + "Host: " + host + "\r\n\r\n"; // 输出指定提示信息 System.out.println("Grabbing /wireshark-labs/INTRO-wireshark-file1.html from " + host); System.out.println("Writing data to " + outputFilePath); try { theSocket = new Socket(host, 80); byte[] buf = new byte[BUFFER_SIZE]; outgoing = theSocket.getOutputStream(); incoming = new DataInputStream(theSocket.getInputStream()); // 发送请求 outgoing.write(packet.getBytes()); outgoing.flush(); File theFile = new File(outputFilePath); FileOutputStream writer = new FileOutputStream(theFile); // 处理文件存在提示 if (theFile.exists()) { System.out.println("It already exists. Contents will be overwritten"); } else { System.out.println("Creating new file: " + theFile.getAbsolutePath()); theFile.getParentFile().mkdirs(); // 确保父目录存在 } // 循环读取响应并写入文件 int numBytes = incoming.read(buf); while (numBytes > 0) { writer.write(buf, 0, numBytes); numBytes = incoming.read(buf); } // 关闭资源 writer.close(); incoming.close(); outgoing.close(); theSocket.close(); } catch (Exception e) { System.err.println("错误: " + e.getMessage()); e.printStackTrace(); } } public static void main(String[] args) throws Exception { SocketandURL(args); } }
使用方式
运行时传递参数:
java HttpFetcher gaia.cs.umass.edu /Users/brichards/message.html
内容的提问来源于stack exchange,提问作者Jaykob Walson
相关产品推荐
相关产品推荐

