给定:
byteString

-----------------------------149742642616556
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain

test
-----------------------------149742642616556--

然后这段代码(未优化):
Pattern pattern = Pattern.compile(BOUNDARY_PATTERN); // "(?m)\\A-+\\d+$"
Matcher matcher = pattern.matcher(byteString);
String boundary = null;
while (matcher.find()) {
    boundary = matcher.group();
    contentType = "multipart/form-data; boundary=" + boundary;
}
LOG.info("Content Type = " + contentType);

@SuppressWarnings("deprecation")
org.apache.commons.fileupload.MultipartStream multipartStream =
        new org.apache.commons.fileupload.MultipartStream(new ByteArrayInputStream(byteString.getBytes()), boundary.getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
multipartStream.readBodyData(bos); // throw error
byte[] byteBody = bos.toByteArray();

抛出这个错误:
org.apache.commons.fileupload.MultipartStream$MalformedStreamException: Stream ended unexpectedly
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:1005)
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:903)
    at java.io.InputStream.read(InputStream.java:101)
    at org.apache.commons.fileupload.util.Streams.copy(Streams.java:100)
    at org.apache.commons.fileupload.util.Streams.copy(Streams.java:70)
    at org.apache.commons.fileupload.MultipartStream.readBodyData(MultipartStream.java:593)

这里可能有什么问题?我很感激这里的帮助。

最佳答案

该问题似乎是由于行尾错误和检索边界的方式造成的。 根据来自 RFC2046SO answer 引用:



问题恰恰在于两点: 行尾类型 边界参数值前面的两个连字符

行尾

由于您的代码没有准确显示 byteString 的值,我尝试了 LF ( \n ) 和 CRLF ( \r\n ) 行尾,看看会发生什么。

坏的 行尾(即不是 CRLF)是 时,该问题似乎重现了 最后一个边界 ,如下所示:

String byteString=
    "-----------------------------149742642616556\r\n" +
    "Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"\r\n" +
    "Content-Type: text/plain; charset=UTF-8\r\n" +
    "\r\n" +
    "test\r\n" + // <-- only \n here lead to a MalformedStreamException
    "-----------------------------149742642616556--\r\n";

听起来 MultipartStream 无法解析边界的开头,因为它没有在上一行中捕获行的右端 (CRLF)。 因此,我使用了 LF 终止符,您应该将它们替换为 CRLF 终止符。

边界格式

RFC 告诉我们边界定界符是两个连字符 + 边界参数 + CRLF。您的正则表达式不仅捕获边界参数值,还包括两个连字符。所以我替换了这部分:
// capturing group = boundary parameter value
String regexp="(?m)\\A--(-*\\d+)$";
// [...]
while (matcher.find()) {
    boundary = matcher.group(1);
    // [...]
}

工作代码

可作为 MCVE 运行

您将在下面找到的代码可以在没有 Tomcat 的控制台中运行。只需要 commons-fileupload-1.3.3-bin.tar.gzcommons-io-2.6-bin.tar.gz

要查看 MultipartStream 解析的内容,我在 bos 调用中暂时将 System.out 替换为 readBodyData() (如评论中所述)。
  • 编译:
    javac Test.java -classpath ./commons-fileupload-1.3.3-bin/commons-fileupload-1.3.3.jar
    
  • 运行:
    java -classpath ./commons-fileupload-1.3.3-bin/commons-fileupload-1.3.3.jar:./commons-io-2.6/commons-io-2.6.jar:. Test
    

  • 代码本身
    import java.util.regex.*;
    import java.io.*;
    import org.apache.commons.fileupload.*;
    
    public class Test {
        public final static void main(String[] argv) {
        String byteString=
            "-----------------------------149742642616556\r\n" +
            "Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"\r\n" +
            "Content-Type: text/plain; charset=UTF-8\r\n" +
            "\r\n" +
            "test\r\n" + // <-- only \n here lead to a MalformedStreamException
            "-----------------------------149742642616556--\r\n";
    
        String regexp="(?m)\\A--(-*\\d+)$"; // edited regexp to catch the right boundary
    
        Pattern pattern = Pattern.compile(regexp);
        Matcher matcher = pattern.matcher(byteString);
        String boundary = null;
        String contentType=null;
        while (matcher.find()) {
            boundary = matcher.group(1);
            contentType = "multipart/form-data; boundary=\"" + boundary + "\"";
        }
    
        System.out.println("boundary = \"" + boundary + "\"");
    
        @SuppressWarnings("deprecation")
            org.apache.commons.fileupload.MultipartStream multipartStream =
            new org.apache.commons.fileupload.MultipartStream
            (new ByteArrayInputStream(byteString.getBytes()), boundary.getBytes());
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
    
        try {
            // Use the commented line instead the following one
            // To see what the multipartStream is reading (for debug)
            // multipartStream.readBodyData(System.out);
            multipartStream.readBodyData(bos);
        } catch (MultipartStream.MalformedStreamException e) {
            System.out.println("Malformed Exception " + e.getMessage());
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        byte[] byteBody = bos.toByteArray();
    
        // Displaying the body read
        for(byte c : byteBody) {
            System.out.format("%c", c);
        }
        System.out.println();
        }
    }
    

    输出:
    boundary = "---------------------------149742642616556"
    -----------------------------149742642616556
    Content-Disposition: form-data; name="file"; filename="test.txt"
    Content-Type: text/plain; charset=UTF-8
    
    test
    

    关于java - MalformedStreamException : Stream ended unexpectedly,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53500627/

    10-12 06:02