Сервлет 3.0, использующий @MultipartConfig, выдает исключение при использовании getPart () - PullRequest
3 голосов
/ 05 апреля 2011

Я получаю странное поведение с server-api 3.0 при использовании @MultipartConfig.Когда я вызываю сервлет со страницы jsp, он работает на 100%, но когда я звоню сервлету из моего собственного клиента java (используя API java.net), я получаю исключение.ниже мой исходный код и вывод, который я получаю в обоих сценариях.

Я использую Java 1.6.0 и запускаю сервлет на apache-tomcat-7.0.11.

Servet:

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

@WebServlet(urlPatterns="/MultipartUploadServlet" , name="MultipartUploadServlet")
@MultipartConfig(location="/tmp", maxFileSize = 10485760L)
public class MultipartUploadServlet extends HttpServlet{

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("MultipartUploadServlet.doPost");
        try {

            System.out.println("Print out the request header");
            Enumeration<String> hn = req.getHeaderNames();
            while(hn.hasMoreElements()) {
                String n = hn.nextElement();
                System.out.println(n + " [" + req.getHeader(n) + "]");
            }

            Collection<Part> requestParts = req.getParts();
            System.out.println("there are [" + requestParts.size() +"] multiparts");


            System.out.println("printing out request inputstream");
            InputStream is = req.getInputStream();
            int charRead = 0;
            System.out.println("[");
            while((charRead = is.read()) != -1){
                System.out.print((char)charRead);
            }
            is.close();

            System.out.println("]");

        } catch (Exception excp) {
            excp.printStackTrace();
        } 
    }

}

JSP-клиент

<html>
    <head></head>
    <body>
        <p>Commons File Upload Example</p>
        <form action="MultipartUploadServlet" enctype="multipart/form-data" method="post">
            <input type="file" name="file1"><br>
            <input type="Submit" value="Upload File"><br>s
        </form>
    </body>
</html>

вывод на tomcat с использованием jsp-клиента

host [localhost:8080]
user-agent [Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13]
accept [text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8]
accept-language [en-us,en;q=0.5]
accept-encoding [gzip,deflate]
accept-charset [ISO-8859-1,utf-8;q=0.7,*;q=0.7]
keep-alive [115]
connection [keep-alive]
referer [http://localhost:8080/scrappyWeb/test.jsp]
cookie [JSESSIONID=06A3E14F91D4B8E558B7438B1D9C7E99]
content-type [multipart/form-data; boundary=---------------------------1137522503144128232716531729]
content-length [223]
there are [1] multiparts

Java-клиент

package com.scrappy.web.client.compass.verification;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class TestClient {

    public static void main(String ... aaa)  {
        System.setProperty("http.keepAlive", "false");

        String boundary = "---------------------------" + Long.toHexString(System.currentTimeMillis());
        try {
            URLConnection connection = new URL("http://localhost:8080/scrappyWeb/MultipartUploadServlet").openConnection();
            ((HttpURLConnection)connection).setRequestMethod("POST");
            ((HttpURLConnection)connection).setConnectTimeout(60000);
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13"); // Do as if you're using Firefox 3.6.3.
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            connection.setRequestProperty("keep-alive", "115");
            connection.setRequestProperty("accept-encoding", "gzip,deflate");
            connection.setRequestProperty("connection", "keep-alive");
            connection.setRequestProperty("accept-charset","ISO-8859-1,utf-8;q=0.7,*;q=0.7");
            connection.setRequestProperty("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            PrintWriter writer = null;
            OutputStream output = connection.getOutputStream();

            String charset = "UTF-8";

            File textFile = new File("/Users/christiaan/test.txt");

            writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
            writer.println("--" + boundary);
            writer.println("Content-Disposition: form-data; name=\"file1\"; filename=\"" + textFile.getName() + "\"");
            writer.println("Content-Type: text/plain");
            writer.println();
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(new FileInputStream(textFile), charset));
                for (String line; (line = reader.readLine()) != null;) {
                    writer.println(line);
                }
            } finally {
                if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
            }
            writer.println(); // Important! Indicates end of binary boundary.

            // End of multipart/form-data.
            writer.println("--" + boundary + "--");
            writer.close();

         ((HttpURLConnection)connection).getResponseCode();

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

Вывод на Tomcat с использованием Java-клиента

user-agent [Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13]
content-type [multipart/form-data; boundary=---------------------------12f24455f6f]
accept-encoding [gzip,deflate]
accept-charset [ISO-8859-1,utf-8;q=0.7,*;q=0.7]
accept [text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8]
host [localhost:8080]
connection [close]
content-length [183]
java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: Stream ended unexpectedly
    at org.apache.catalina.connector.Request.parseParts(Request.java:2639)
    at org.apache.catalina.connector.Request.getParts(Request.java:2539)
    at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1077)
    at com.scrappy.web.servlet.compass.verification.MultipartUploadServlet.doPost(MultipartUploadServlet.java:31)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:498)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:394)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)
Caused by: org.apache.tomcat.util.http.fileupload.FileUploadException: Stream ended unexpectedly
    at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:336)
    at org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:129)
    at org.apache.catalina.connector.Request.parseParts(Request.java:2609)
    ... 22 more
Caused by: org.apache.tomcat.util.http.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
    at org.apache.tomcat.util.http.fileupload.MultipartStream.readHeaders(MultipartStream.java:488)
    at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:861)
    at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:827)
    at org.apache.tomcat.util.http.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:282)
    at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:302)
    ... 24 more

Единственное реальное отличие, которое я вижу в заголовках:длина контента.Но что меня поразило, так это то, что если я получаю inputStream из запроса HttpServletRequest и распечатываю его, он печатает все в файле test.txt, как и должно быть. post

Должно быть, я что-то упускаю или чего-то не понимаю, надеюсь, кто-то может помочь!

Ответы [ 3 ]

6 голосов
/ 05 апреля 2011

Mac / Linux использует \n в качестве разделителя строк по умолчанию на println(), в то время как HTTP предписывает \r\n (и это значение по умолчанию в Windows). Извините, это была довольно глупая ошибка в учебнике URLConnection. Я исправлю это как можно скорее.

3 голосов
/ 05 апреля 2011

Используя wireshark для объединения отправленных пакетов, я увидел, что пакет MIME Multipart был искажен. Я в основном изменил клиента, чтобы написать материал для размещения контента, чтобы использовать прямой поток вывода, а не PrintWriter. Кажется, это работает, но я не уверен, почему, так как оба так же одно и то же.

Спасибо за Вайнет Рейнольдс за указание на WireShark

Вот новый клиент:

package com.scrappy.web.client.compass.verification;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class TestClient {

    public static void main(String ... aaa)  {
        System.setProperty("http.keepAlive", "false");

        String boundary = "---------------------------" +  Long.toHexString(System.currentTimeMillis());
        try {
            URLConnection connection = new URL("http://localhost:8080/scrappyWeb/MultipartUploadServlet").openConnection();
            ((HttpURLConnection)connection).setRequestMethod("POST");
            ((HttpURLConnection)connection).setConnectTimeout(6000000);
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13"); // Do as if you're using Firefox 3.6.3.
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            connection.setRequestProperty("accept-encoding", "gzip,deflate");
            connection.setRequestProperty("connection", "keep-alive");
            connection.setRequestProperty("accept-charset","ISO-8859-1,utf-8;q=0.7,*;q=0.7");
            connection.setRequestProperty("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
            connection.setRequestProperty("accept-language", "en-us,en;q=0.5");
            OutputStream output = connection.getOutputStream();

            String charset = "UTF-8";

            File textFile = new File("/Users/christiaan/test.txt");
            output.write(("\r\n\r\n--" + boundary +"\r\n").getBytes());
            output.write(("Content-Disposition: form-data; name=\"file1\"; filename=\"" + textFile.getName() + "\"\r\n").getBytes());
            output.write(("Content-Type: text/plain\r\n").getBytes());
            output.write(("\r\n").getBytes());


            PrintWriter writer = null;
            writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(new FileInputStream(textFile), charset));
                for (String line; (line = reader.readLine()) != null;) {
                    writer.println(line);
                }
            } finally {
                if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
            }

            // End of multipart/form-data.
            output.write(("\r\n").getBytes());
            output.write(("--" + boundary +"--\r\n").getBytes());
            output.flush();
            writer.close();



         ((HttpURLConnection)connection).getResponseCode();



        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
1 голос
/ 07 апреля 2011

На ум приходят две вещи.

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

Приветствия

...