返回带有Java Web服务器的文件时出错

返回带有Java Web服务器的文件时出错,java,multithreading,io,webserver,outputstream,Java,Multithreading,Io,Webserver,Outputstream,我用Java编写的这个基本、简单的Web服务器遇到了麻烦。出于某种原因,不是将“200 OK”或“404 Not Found”单独发送到浏览器,而是将它们写入正在检索的任何文件中。例如,如果我尝试获取index.html文件,则返回: …而不是浏览器试图编译HTML。 当试图获取图像时,情况更糟,因为服务器试图将“200OK”和内容类型附加到该文件时,该文件已损坏。有人能提供一些见解,说明如何将状态行和内容类型与实际的HTML/JPG文件分开发送吗?当我注释掉“os.writeBytes(st

我用Java编写的这个基本、简单的Web服务器遇到了麻烦。出于某种原因,不是将“200 OK”或“404 Not Found”单独发送到浏览器,而是将它们写入正在检索的任何文件中。例如,如果我尝试获取index.html文件,则返回:

…而不是浏览器试图编译HTML。 当试图获取图像时,情况更糟,因为服务器试图将“200OK”和内容类型附加到该文件时,该文件已损坏。有人能提供一些见解,说明如何将状态行和内容类型与实际的HTML/JPG文件分开发送吗?当我注释掉“os.writeBytes(statusLine)”等时,错误完全消失了,但我仍然希望将这些消息发送到浏览器…只是不与文件合并。任何帮助都将不胜感激

import java.io.*;
import java.net.*;
import java.util.*;

final class HttpRequest implements Runnable {
    final static String CRLF = "\r\n";
    Socket socket;

    // Constructor
    public HttpRequest(Socket socket) throws Exception {
        this.socket = socket;
    }

    // Implement the run() method of the Runnable interface.
    public void run() {
        try {
            processRequest();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    private static void sendBytes(FileInputStream fis, OutputStream os) 
    throws Exception {
    // Construct a 1K buffer to hold bytes on their way to the socket.
    byte[] buffer = new byte[1024];
    int bytes = 0;

    // Copy requested file into the socket's output stream.
    while((bytes = fis.read(buffer)) != -1 ) {
        os.write(buffer, 0, bytes);
        }
    }

    private static String contentType(String fileName) {
    if(fileName.endsWith(".htm") || fileName.endsWith(".html")) {
        return "text/html";
    }
    if(fileName.endsWith(".jpeg") || fileName.endsWith(".jpg")) {
    return "image/jpeg";
    }
    if(fileName.endsWith(".gif")) {
    return "image/gif";
    }
    return "application/octet-stream";
    }

    private void processRequest() throws Exception {
        // Get a reference to the socket's input and output streams.
        InputStream is = socket.getInputStream();
        DataOutputStream os = new DataOutputStream(socket.getOutputStream());

        // Set up input stream filters.
        BufferedReader br = new BufferedReader(new InputStreamReader(is));

        // Get the request line of the HTTP request message.
        String requestLine = new String(br.readLine());

        // Display the request line.
        System.out.println();
        System.out.println(requestLine);

        // Get and display the header lines.
        String headerLine = null;
        while ((headerLine = br.readLine()).length() != 0) {
            System.out.println(headerLine);
        }

    // Extract the filename from the request line.
    StringTokenizer tokens = new StringTokenizer(requestLine);
    tokens.nextToken(); // skip over the method, which should be "GET"
    String fileName = tokens.nextToken();
    // Prepend a "." so that file request is within the current directory.
    fileName = "." + fileName;

    // Open the requested file.
    FileInputStream fis = null;
    boolean fileExists = true;
    try {
    fis = new FileInputStream(fileName);
    } catch (FileNotFoundException e) {
    fileExists = false;
    }

    // Construct the response message.
    String statusLine = null;
    String contentTypeLine = null;
    String entityBody = null;
    if (fileExists) {
    statusLine = "200 OK" + CRLF;
    contentTypeLine = "Content-type: " + 
        contentType( fileName ) + CRLF;
    } else {
    statusLine = "404 NOT FOUND" + CRLF;
    contentTypeLine = "Content Not Found!" + CRLF;
    entityBody = "<HTML>" + 
        "<HEAD><TITLE>Not Found</TITLE></HEAD>" +
        "<BODY>Not Found</BODY></HTML>";
    }

    // Send the status line.
    os.writeBytes(statusLine);

    // Send the content type line.
    os.writeBytes(contentTypeLine);

    // Send a blank line to indicate the end of the header lines.
    os.writeBytes(CRLF);

    // Send the entity body.
    if (fileExists) {
    sendBytes(fis, os);
    fis.close();
    } else {
    os.writeBytes("File DNE: Content Not Found!");
    }

        // Close streams and socket.
        os.close();
        br.close();
        socket.close();
    }
    public static void main(String[] args) throws Exception {
        final ServerSocket ss = new ServerSocket(6789);
        while (true)
            new HttpRequest(ss.accept()).run();
    }
}
import java.io.*;
导入java.net。*;
导入java.util.*;
最后一个类HttpRequest实现Runnable{
最终静态字符串CRLF=“\r\n”;
插座;
//建造师
公共HttpRequest(套接字)引发异常{
this.socket=socket;
}
//实现Runnable接口的run()方法。
公开募捐{
试一试{
processRequest();
}捕获(例外e){
系统输出打印ln(e);
}
}
私有静态void sendBytes(FileInputStream fis、OutputStream os)
抛出异常{
//构造一个1K缓冲区,在字节到达套接字的过程中保存字节。
字节[]缓冲区=新字节[1024];
int字节=0;
//将请求的文件复制到套接字的输出流中。
而((字节=fis.read(缓冲区))!=-1){
写操作(缓冲区,0,字节);
}
}
私有静态字符串contentType(字符串文件名){
if(fileName.endsWith(“.htm”)| | fileName.endsWith(“.html”)){
返回“text/html”;
}
if(fileName.endsWith(“.jpeg”)| | fileName.endsWith(“.jpg”)){
返回“图像/jpeg”;
}
if(fileName.endsWith(“.gif”)){
返回“image/gif”;
}
返回“应用程序/八位字节流”;
}
私有void processRequest()引发异常{
//获取对套接字的输入和输出流的引用。
InputStream=socket.getInputStream();
DataOutputStream os=新的DataOutputStream(socket.getOutputStream());
//设置输入流过滤器。
BufferedReader br=新的BufferedReader(新的InputStreamReader(is));
//获取HTTP请求消息的请求行。
String requestLine=新字符串(br.readLine());
//显示请求行。
System.out.println();
System.out.println(请求行);
//获取并显示标题行。
字符串标题行=null;
while((headerLine=br.readLine()).length()!=0){
系统输出打印LN(车头线);
}
//从请求行提取文件名。
StringTokenizer令牌=新的StringTokenizer(requestLine);
tokens.nextToken();//跳过该方法,该方法应为“GET”
字符串文件名=tokens.nextToken();
//在“.”前面加上前缀,使文件请求位于当前目录中。
fileName=“.”+文件名;
//打开请求的文件。
FileInputStream fis=null;
布尔fileExists=true;
试一试{
fis=新文件输入流(文件名);
}catch(filenotfounde异常){
fileExists=false;
}
//构造响应消息。
字符串statusLine=null;
字符串contentTypeLine=null;
字符串entityBody=null;
如果(文件存在){
statusLine=“200正常”+CRLF;
contentTypeLine=“内容类型:”+
contentType(文件名)+CRLF;
}否则{
statusLine=“404未找到”+CRLF;
contentTypeLine=“找不到内容!”+CRLF;
entityBody=”“+
“找不到”+
“未找到”;
}
//发送状态行。
操作系统写入字节(状态行);
//发送内容类型行。
写字节(contentTypeLine);
//发送一个空行以指示标题行的结尾。
操作系统写入字节(CRLF);
//发送实体体。
如果(文件存在){
sendBytes(fis、os);
fis.close();
}否则{
os.writeBytes(“文件DNE:未找到内容!”);
}
//关闭流和套接字。
os.close();
br.close();
socket.close();
}
公共静态void main(字符串[]args)引发异常{
最终服务器插座ss=新服务器插座(6789);
while(true)
新的HttpRequest(ss.accept()).run();
}
}

我相信您丢失了一个CRLF。在状态行的末尾不需要额外的一个吗

200行 内容类型:xxxx

当然,您可以阅读HTTP规范,或者执行wireshark跟踪:)

更新:是的,你有很多问题。阅读一篇简单的文章 总结

但无论如何,你需要说“HTTP/1.0 200 OK”作为例子

http://www.somehost.com/path/file.html
首先打开主机www.somehost.com端口80的套接字(使用默认端口80,因为URL中未指定任何端口)。然后,通过套接字发送如下内容:

GET /path/file.html HTTP/1.0
From: someuser@jmarshall.com
User-Agent: HTTPTool/1.0
[blank line here]
服务器应通过相同的套接字发送以下响应:

HTTP/1.0 200 OK
Date: Fri, 31 Dec 1999 23:59:59 GMT
Content-Type: text/html
Content-Length: 1354

<html>
<body>
<h1>Happy New Millennium!</h1>
(more file contents)
  .
  .
  .
</body>
</html>
HTTP/1.0 200正常
日期:1999年12月31日星期五23:59:59 GMT
内容类型:text/html
内容长度:1354
新千年快乐!
(更多文件内容)
.
.
.
在statusLine=“200正常”+CRLF

您没有正确的请求,您缺少HTTP/1.1

右代码:

if(文件存在){
statusLine=“HTTP/1.1 200正常”+CRLF;
contentTypeLine=“内容类型:”+
contentType(文件名)+CRLF+CRLF;
}否则{
statusLine=“404未找到”+CRLF;
contentTypeLine=“找不到内容!”+CRLF;
entityBody=”“+
“找不到”+
“未找到”;

}
我不太明白我在哪里会错过一个CRLF…我在状态行本身中有一个,以及在发送entit之前