как позволить Java HttpServer обрабатывать пост-запрос для загрузки файла - PullRequest
2 голосов
/ 23 июля 2011

Прежде всего, мой вопрос о HttpServer в Java для обработки POST-запроса от клиента, не о Java-клиенте, который может загружать файл на веб-сервер.

OK. Я использую облегченный HttpServer в Java для обработки "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 или любой другой веб-браузер делают с формой -> input type = 'file'?

Если я использую ServerSocket для обработки HTTP-запроса, я просто получаю InputStream запроса, а затем весь контент (включая заголовки HTTP и содержимое загружаемого файла) будет проходить через этот InputStream, верно?

Приведенный выше код может анализировать заголовки, но, похоже, из браузера больше ничего не отправляется.

Может кто-нибудь, пожалуйста, помогите?

Спасибо

Ответы [ 3 ]

2 голосов
/ 23 июля 2011

Он зависает, потому что клиент (в моем случае Chrome) не предоставляет Content-Length. RFC 1867 довольно расплывчато. Это как бы подсказывает, но не навязывает и не имеет примера. Очевидно клиенты не всегда отправляли бы это. Код должен защищать от недостающей длины. Вместо этого он проходит цикл, пока не достигнет конца файла. Потом зависает.

Иногда полезно использовать отладчик.

0 голосов
/ 03 июня 2018

Это старый вопрос, но в случае, если другие натолкнутся на него, ища ответ на заглавный вопрос, а не на конкретную ошибку, упомянутую в деталях (у меня такое ощущение, что большинство зрителей) ... Я бы порекомендовал вам сохранить себе боль и не используйте приведенный фрагмент кода.

Это не HTTP-сервер, и он выйдет из строя в любом случае, кроме простейшего варианта использования (и, очевидно, даже тогда), а также не будет следовать основным нормам хорошего кодирования. Даже если бы это было не так, он явно заявляет, что поддерживает только текстовые файлы (и действительно читает весь файл в строку), и даже в этом случае неправильно обрабатывает кодировки charset.

При этом вы, вероятно, здесь ищете один из двух ответов - как вы можете принять загрузку файлов в вашем приложении или как сам HTTP-сервер реализует это.

Если вы заинтересованы в том, как сделать это для развлечения или в образовательных целях, я настоятельно рекомендую прочитать RFC (RFC 7230 для ядра HTTP / 1.1, RFC 2046, раздел 5.1 для многочастного анализа) и попробовать написать простой HTTP- как сервер, как этот. Это хороший способ обучения, особенно если у вас есть опытный разработчик, который проанализирует ваш код, даст вам советы и поможет найти наиболее эффективные варианты. В качестве упражнения вы можете даже начать с приведенного выше кода и попытаться исправить его недостатки и сделать его немного более удобным для использования, хотя, тем не менее, не путайте это с реальным HTTP-сервером для использования в производстве.

Если вам все это безразлично и вы просто хотите добиться успеха в реальном приложении, я рекомендую просто использовать надлежащий HTTP-сервер. Вокруг их много, что позволит вам делать то, что пытается описанный выше фрагмент кода, с гораздо меньшим количеством кода и ошибок.

Отказ от ответственности: я являюсь автором JLHTTP - облегченного HTTP-сервера Java , который представляет собой крошечный однофайловый сервер (или ~ 50K / 35K jar) без зависимостей, которые стремятся быть RFC-совместимыми и поддерживает загрузку файлов среди прочего. Не стесняйтесь использовать его или просто просмотрите код и документацию, чтобы найти относительно простой пример того, как может работать HTTP-сервер и многоэтапный синтаксический анализ (загрузка файлов), как это реализовано самим сервером, так и то, как вы можете использовать это в своем приложении. Или посмотрите любой другой HTTP-сервер, который может сделать то же самое.

0 голосов
/ 23 июля 2011

Это лот-код:)

Давайте начнем с перемещения вызовов break; из операторов if внутри раздела POST, начиная со строки 83. Нам нужно выяснить, что висят и операторы while могут легко стать проблемой.

Это поможет нам выяснить, где проблема.

Если вы просто хотите, чтобы это сработало, и вам все равно, в чем заключается ошибка, это своего рода переизобретение колеса, существует масса библиотек, чтобы сделать эту операцию одной или двумя строками.

Вот хороший пример: http://www.servlets.com/cos/ - посмотрите на класс MultiPartRequest (источник доступен для скачивания)

...