首先,我的问题是Java中的HttpServer处理来自客户端的POST请求,不关于可以将文件上传到Web服务器的Java客户端。
行。我在Java中使用一个轻量级的HttpServer来处理“GET”|| “POST”请求。 HttpServer的源代码是从http://www.prasannatech.net/2008/11/http-web-server-java-post-file-upload.html复制的。
/*
* HTTPPOSTServer.java
* Author: S.Prasanna
* @version 1.00
*/
import java.io.*;
import java.net.*;
import java.util.*;
public class HTTPPOSTServer extends Thread {
static final String HTML_START =
"<html>" +
"<title>HTTP POST Server in java</title>" +
"<body>";
static final String HTML_END =
"</body>" +
"</html>";
Socket connectedClient = null;
BufferedReader inFromClient = null;
DataOutputStream outToClient = null;
public HTTPPOSTServer(Socket client) {
connectedClient = client;
}
public void run() {
String currentLine = null, postBoundary = null, contentength = null, filename = null, contentLength = null;
PrintWriter fout = null;
try {
System.out.println( "The Client "+
connectedClient.getInetAddress() + ":" + connectedClient.getPort() + " is connected");
inFromClient = new BufferedReader(new InputStreamReader (connectedClient.getInputStream()));
outToClient = new DataOutputStream(connectedClient.getOutputStream());
currentLine = inFromClient.readLine();
String headerLine = currentLine;
StringTokenizer tokenizer = new StringTokenizer(headerLine);
String httpMethod = tokenizer.nextToken();
String httpQueryString = tokenizer.nextToken();
System.out.println(currentLine);
if (httpMethod.equals("GET")) {
System.out.println("GET request");
if (httpQueryString.equals("/")) {
// The default home page
String responseString = HTTPPOSTServer.HTML_START +
"<form action=\"http://127.0.0.1:5000\" enctype=\"multipart/form-data\"" +
"method=\"post\">" +
"Enter the name of the File <input name=\"file\" type=\"file\"><br>" +
"<input value=\"Upload\" type=\"submit\"></form>" +
"Upload only text files." +
HTTPPOSTServer.HTML_END;
sendResponse(200, responseString , false);
} else {
sendResponse(404, "<b>The Requested resource not found ...." +
"Usage: http://127.0.0.1:5000</b>", false);
}
}
else { //POST request
System.out.println("POST request");
do {
currentLine = inFromClient.readLine();
if (currentLine.indexOf("Content-Type: multipart/form-data") != -1) {
String boundary = currentLine.split("boundary=")[1];
// The POST boundary
while (true) {
currentLine = inFromClient.readLine();
if (currentLine.indexOf("Content-Length:") != -1) {
contentLength = currentLine.split(" ")[1];
System.out.println("Content Length = " + contentLength);
break;
}
}
//Content length should be < 2MB
if (Long.valueOf(contentLength) > 2000000L) {
sendResponse(200, "File size should be < 2MB", false);
}
while (true) {
currentLine = inFromClient.readLine();
if (currentLine.indexOf("--" + boundary) != -1) {
filename = inFromClient.readLine().split("filename=")[1].replaceAll("\"", "");
String [] filelist = filename.split("\\" + System.getProperty("file.separator"));
filename = filelist[filelist.length - 1];
System.out.println("File to be uploaded = " + filename);
break;
}
}
String fileContentType = inFromClient.readLine().split(" ")[1];
System.out.println("File content type = " + fileContentType);
inFromClient.readLine(); //assert(inFromClient.readLine().equals("")) : "Expected line in POST request is "" ";
fout = new PrintWriter(filename);
String prevLine = inFromClient.readLine();
currentLine = inFromClient.readLine();
//Here we upload the actual file contents
while (true) {
if (currentLine.equals("--" + boundary + "--")) {
fout.print(prevLine);
break;
}
else {
fout.println(prevLine);
}
prevLine = currentLine;
currentLine = inFromClient.readLine();
}
sendResponse(200, "File " + filename + " Uploaded..", false);
fout.close();
} //if
}while (inFromClient.ready()); //End of do-while
}//else
} catch (Exception e) {
e.printStackTrace();
}
}
public void sendResponse (int statusCode, String responseString, boolean isFile) throws Exception {
String statusLine = null;
String serverdetails = "Server: Java HTTPServer";
String contentLengthLine = null;
String fileName = null;
String contentTypeLine = "Content-Type: text/html" + "\r\n";
FileInputStream fin = null;
if (statusCode == 200)
statusLine = "HTTP/1.1 200 OK" + "\r\n";
else
statusLine = "HTTP/1.1 404 Not Found" + "\r\n";
if (isFile) {
fileName = responseString;
fin = new FileInputStream(fileName);
contentLengthLine = "Content-Length: " + Integer.toString(fin.available()) + "\r\n";
if (!fileName.endsWith(".htm") && !fileName.endsWith(".html"))
contentTypeLine = "Content-Type: \r\n";
}
else {
responseString = HTTPPOSTServer.HTML_START + responseString + HTTPPOSTServer.HTML_END;
contentLengthLine = "Content-Length: " + responseString.length() + "\r\n";
}
outToClient.writeBytes(statusLine);
outToClient.writeBytes(serverdetails);
outToClient.writeBytes(contentTypeLine);
outToClient.writeBytes(contentLengthLine);
outToClient.writeBytes("Connection: close\r\n");
outToClient.writeBytes("\r\n");
if (isFile) sendFile(fin, outToClient);
else outToClient.writeBytes(responseString);
outToClient.close();
}
public void sendFile (FileInputStream fin, DataOutputStream out) throws Exception {
byte[] buffer = new byte[1024] ;
int bytesRead;
while ((bytesRead = fin.read(buffer)) != -1 ) {
out.write(buffer, 0, bytesRead);
}
fin.close();
}
public static void main (String args[]) throws Exception {
ServerSocket Server = new ServerSocket (5000);
System.out.println ("HTTP Server Waiting for client on port 5000");
while(true) {
Socket connected = Server.accept();
(new HTTPPOSTServer(connected)).start();
}
}
}
我仔细阅读了代码,我认为代码应该没问题。
但是当我尝试上传文件时,它会打印出POST请求,然后挂起并永远不会收到任何字节。
如果您愿意,可以直接运行上述源代码。启动后,您可以在浏览器中键入127.0.0.1:5000,它将显示文件上传,如果我尝试上传文件,它将在打印PoST请求后挂起。
如果您无聊阅读代码,请问以下更简单的问题?
那么,Chrome或任何其他网络浏览器对表单的确做什么 - &gt;输入类型='文件'?
如果我使用ServerSocket来处理HTTP请求,我只需要获取请求的InputStream,然后所有内容(包括HTTP头和上传文件的内容)将通过该InputStream,对吧?
以上代码可以分析标题,但似乎没有任何内容从浏览器发送。
任何人都可以帮忙吗?
由于
答案 0 :(得分:2)
它挂起是因为客户端(Chrome,在我的情况下)不提供Content-Length
。
RFC 1867对此非常模糊。它有点暗示但不强迫它,也没有例子。显然客户不会总是发送它。代码应该防止丢失长度。相反,它会经历循环,直到它到达文件末尾。然后就挂了。
有时使用调试器非常有用。
答案 1 :(得分:0)
多数代码:)
让我们从POST部分中的if语句中移出break;
调用开始,从第83行开始。我们需要弄清楚什么是挂起的,而那些语句很容易成为问题。
这将帮助我们找出问题所在。
如果你只是想让它工作,而不是真正关心这个bug是什么,这就是重新发明轮子,有很多库可以让它成为一两行操作。
这是一个很好的:http://www.servlets.com/cos/ - 查看MultiPartRequest
类(可下载源代码)
答案 2 :(得分:0)
这是一个老问题,但万一其他人偶然发现它寻找标题问题的答案而不是细节中提到的具体错误(我有一种感觉是大多数观众)......我建议你保存你自己的痛苦,而不是使用上面的代码片段。
它不是HTTP服务器,除了最简单的用例(显然甚至是那个)之外,它都会失败,也不会遵循基本的良好编码实践。即使它不是为了它,它明确声明它只支持文本文件(实际上将整个文件读入一个字符串),即使这样也不能正确处理字符集编码。
话虽如此,您可能正在寻找两个答案中的一个 - 如何接受应用程序中的文件上传,或者HTTP服务器本身如何实现这一点。
如果您对如何为了娱乐或教育目的感兴趣,我强烈建议您阅读RFC(用于核心HTTP / 1.1的RFC 7230,用于多部分解析的RFC 2046第5.1节)并尝试编写简单的HTTP-像这样的服务器。这是一种很好的学习方式,特别是如果您有经验丰富的开发人员来审核您的代码并为您提供提示并帮助您找到边缘案例。作为练习,您甚至可以从上面的代码开始,尝试修复它的缺点并使其更加可用,但是,不要将它与真正的HTTP服务器混淆以用于生产。
如果您不关心所有这些并且只想在真实的应用程序中完成工作,我建议您只使用正确的HTTP服务器。它们中有很多可以让你做上面代码片段尝试的内容,代码和错误更少。
免责声明:我是JLHTTP - The Java Lightweight HTTP Server的作者,这是一个很小的单文件服务器(或~50K / 35K jar),没有依赖性,力求符合RFC标准,并支持文件上传等。随意使用它,或者只是浏览代码和文档,以获得HTTP服务器和多部分解析(文件上载)如何工作的相对简单的示例,包括服务器本身实现以及如何在应用程序中使用它。或者查看那些可以执行相同操作的许多其他HTTP服务器。