java 如何仅使用标准网络库发送 HTTP 响应?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3696986/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I send an HTTP Response using only standard network libraries?
提问by rownage
I'm working on my first homework project in a web programming class, which is to write a simple web server in Java. I'm at the point where I have data being transmitted back and forth, and to the untrained eye, my baby server seems to be working fine. However, I can't find a way to send appropriate responses. (In other words, an invalid page request would show a 404-ish HTML page, but it still returns a 200 OK status when I view response headers).
我正在网络编程课程中完成我的第一个家庭作业项目,即用 Java 编写一个简单的网络服务器。我正处于来回传输数据的地步,对于未经训练的人来说,我的婴儿服务器似乎工作正常。但是,我找不到发送适当回复的方法。(换句话说,一个无效的页面请求会显示一个 404-ish HTML 页面,但当我查看响应头时它仍然返回 200 OK 状态)。
I'm limited to being able to use standard network libraries for socket management and standard I/O libraries to read and write bytes and strings from an input stream. Here's some pertinent code:
我只能使用标准网络库进行套接字管理,使用标准 I/O 库从输入流中读取和写入字节和字符串。这是一些相关的代码:
From my main...
从我的主要...
ServerSocket servSocket = new ServerSocket(port, 10); // Bind the socket to the port
System.out.println("Opened port " + port + " successfully!");
while(true) {
//Accept the incoming socket, which means that the server process will
//wait until the client connects, then prepare to handle client commands
Socket newDataSocket = servSocket.accept();
System.out.println("Client socket created and connected to server socket...");
handleClient(newDataSocket); //Call handleClient method
}
From the handleClient method...(inside a loop that parses the request method and path)
从 handleClient 方法...(在解析请求方法和路径的循环中)
if(checkURL.compareTo("/status") == 0) { // Check to see if status page has been requested
System.out.println("STATUS PAGE"); // TEMPORARY. JUST TO MAKE SURE WE ARE PROPERLY ACCESSING STATUS PAGE
sendFile("/status.html", dataStream);
}
else {
sendFile(checkURL, dataStream); // If not status, just try the input as a file name
}
From sendFile method...
从 sendFile 方法...
File f = new File(where); // Create the file object
if(f.exists() == true) { // Test if the file even exists so we can handle a 404 if not.
DataInputStream din;
try {
din = new DataInputStream(new FileInputStream(f));
int len = (int) f.length(); // Gets length of file in bytes
byte[] buf = new byte[len];
din.readFully(buf);
writer.write("HTTP/1.1 200 OK\r\n"); // Return status code for OK (200)
writer.write("Content-Length: " + len + "\r\n"); // WAS WRITING TO THE WRONG STREAM BEFORE!
writer.write("Content-Type: "+type+"\r\n\r\n\r\n"); // TODO VERIFY NEW CONTENT-TYPE CODE
out.write(buf); // Writes the FILE contents to the client
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace(); // Not really handled since that's not part of project spec, strictly for debug.
}
}
else {
writer.write("HTTP/1.1 404 Not Found\r\n"); // Attempting to handle 404 as simple as possible.
writer.write("Content-Type: text/html\r\n\r\n\r\n");
sendFile("/404.html", sock);
}
Can anybody explain how, in the conditional from sendFile, I can change the response in the 404 block (Like I said before, the response headers still show 200 OK)? This is bugging the crap out of me, and I just want to use the HTTPResponse class but I can't. (Also, content length and type aren't displayed if f.exists == true.)
谁能解释一下,在来自 sendFile 的条件中,我如何更改 404 块中的响应(就像我之前说的,响应标头仍然显示 200 OK)?这让我很烦,我只想使用 HTTPResponse 类,但我不能。(此外,如果 f.exists == true,则不显示内容长度和类型。)
Thanks!
谢谢!
回答by T.J. Crowder
EditIt looks to me like in the 404 situation, you're sending something like this:
编辑在我看来,在 404 情况下,您发送的内容如下:
HTTP/1.1 404 Not Found
Content-Type: text/html
HTTP/1.1 200 OK
Content-Length: 1234
Content-Type: text/html
...followed by the 404 page. Note the 200 line following the 404. This is because your 404 handling is calling sendFile
, which is outputting the 200 response status code. This is probably confusing the receiver.
...接着是 404 页面。请注意 404 后面的 200 行。这是因为您的 404 处理正在调用sendFile
,它正在输出 200 响应状态代码。这可能会让接收者感到困惑。
Old answer that missed that:
旧答案错过了:
An HTTP response starts with a status line followed (optionally) by a series of headers, and then (optionally) includes a response body. The status line and headers are just lines in a defined format, like (to pick a random example):
HTTP 响应以状态行开头,后跟(可选)一系列标头,然后(可选)包括响应正文。状态行和标题只是定义格式的行,例如(选择一个随机示例):
HTTP/1.0 404 Not Found
To implement your small HTTP server, I'd recommend having a read through the specand seeing what the responses should look like. It's a bit of a conceptual leap, but they really are just lines of text returned according to an agreed format. (Well, it was a conceptual leap for me some years back, anyway. I was used to environments that over-complicated things.)
要实现您的小型 HTTP 服务器,我建议您通读规范并查看响应应该是什么样子。这是一个概念上的飞跃,但它们实际上只是根据商定的格式返回的文本行。(好吧,无论如何,这对我来说是几年前的概念上的飞跃。我已经习惯了使事情过于复杂的环境。)
It can also be helpful to do things like this from your favorite command line:
从您最喜欢的命令行执行以下操作也很有帮助:
telnet www.google.com 80
GET /thispagewontbefound
...and press Enter. You'll get something like this:
...然后按 Enter。你会得到这样的东西:
HTTP/1.0 404 Not Found
Content-Type: text/html; charset=UTF-8
X-Content-Type-Options: nosniff
Date: Sun, 12 Sep 2010 23:01:14 GMT
Server: sffe
Content-Length: 1361
X-XSS-Protection: 1; mode=block
...followed by some HTML to provide a friendly 404 page. The first line above is the status line, the rest are headers. There's a blank line between the status line/headers and the first line of content (e.g., the page).
...后面是一些 HTML 以提供友好的 404 页面。上面的第一行是状态行,其余的是标题。状态行/标题和第一行内容(例如页面)之间有一个空行。
回答by Moritz
The problem you are seeing is most likely related to a missing flush()
on your writer
. Depending on which type of Writer
you use the bytes are first written to a buffer that needs to be flushed to the stream. This would explain why Content-Length
and Content-Type
are missing in the output. Just flush it before you write additional data to the stream.
您看到的问题很可能与flush()
您的writer
. 根据Writer
您使用的类型,字节首先写入需要刷新到流的缓冲区。这将解释为什么Content-Length
和Content-Type
在输出中丢失。只需在将其他数据写入流之前刷新它。
Further you call sendFile("/404.html", sock);
. You did not post the full method here - but I suppose that you call it recursively inside sendFile
and thus send the 200 OK
status for your file /404.html
.
进一步你打电话sendFile("/404.html", sock);
。您没有在此处发布完整的方法 - 但我想您是在内部递归调用它sendFile
,从而发送200 OK
文件的状态/404.html
。
回答by Stephen C
Based on your reported symptoms, I think the real problem is that you are not actually talking to your server at all! The evidence is that 1) you cannot get a 404 response, and 2) a 200 response does not have the content length and type. Neither of these should be possible ... if you are really talking to the code listed above.
根据您报告的症状,我认为真正的问题是您实际上根本没有与服务器通话!证据是 1) 你不能得到 404 响应,2) 200 响应没有内容长度和类型。这些都不应该是可能的......如果你真的在和上面列出的代码交谈。
Maybe:
或许:
- you are talking to an older version of your code; i.e. something is going wrong in your build / deploy cycle,
- you are (mistakenly) trying to deploy / run your code in a web container (Jetty, Tomcat, etc), or
- your client code / browser is actually talking to a different server due to proxying, an incorrect URL, or something like that.
- 您正在使用旧版本的代码;即在您的构建/部署周期中出现问题,
- 您(错误地)尝试在 Web 容器(Jetty、Tomcat 等)中部署/运行您的代码,或者
- 由于代理、不正确的 URL 或类似原因,您的客户端代码/浏览器实际上正在与不同的服务器通信。
I suggest that you add some trace printing / logging at appropriate points of your code to confirm that it is actually being invoked.
我建议您在代码的适当位置添加一些跟踪打印/日志记录,以确认它实际上正在被调用。