簡體   English   中英

在Java中解析包含multipart / form-data請求體的String

[英]Parse a String containing multipart/form-data request body in Java

問題陳述

我認為標題說明了一切:我正在尋找解析包含multipart / form-data HTTP請求的正文部分的String的方法。 即字符串的內容看起來像這樣:

--xyzseparator-blah
Content-Disposition: form-data; name="param1"

hello, world
--xyzseparator-blah
Content-Disposition: form-data; name="param2"

42
--xyzseparator-blah
Content-Disposition: form-data; name="param3"

blah, blah, blah
--xyzseparator-blah--

我希望獲得的是parameters圖,或類似的東西,像這樣。

parameters.get("param1");    // returns "hello, world"
parameters.get("param2");    // returns "42"
parameters.get("param3");    // returns "blah, blah, blah"
parameters.keys();           // returns ["param1", "param2", "param3"]

更多標准

  • 如果我不必提供分隔符(在這種情況下是xyzseparator-blah ),那將是最好的,但如果我必須,我可以忍受它。
  • 我正在尋找一個基於庫的解決方案,可能來自主流庫(如“Apache Commons”或類似的東西)。
  • 我想避免推出自己的解決方案,但在現階段,我恐怕不得不這樣做。 原因:雖然通過一些字符串操作分割/解析上面的例子似乎微不足道,但真正的多部分請求體可以有更多的標題。 除此之外,我不想重新發明(並且更少重新測試!)輪子:)

替代方案

如果有一個滿足上述標准的解決方案,但其輸入是Apache HttpRequest ,而不是String ,那也是可以接受的。 (基本上我確實收到了HttpRequest ,但是我正在使用的內部庫是這樣構建的,它將此請求的主體作為String提取,並將其傳遞給負責進行解析的類。但是,如果需要的話是的,我也可以直接在HttpRequest上工作。)

相關問題

無論我如何嘗試通過Google找到答案,在SO上,以及在其他論壇上,解決方案似乎總是使用commons fileupload來完成各個部分。 例如: 這里這里這里這里這里 ......但是,在該解決方案中使用的parseRequest方法需要一個RequestContext ,我沒有(只有HttpRequest )。

在上面的一些答案中也提到的另一種方法是從HttpServletRequest獲取參數(但同樣,我只有HttpRequest )。

編輯 :換句話說:我可以包括通用FileUpload(我有機會的話),但不會幫助我,因為我有一個HttpRequest ,和通用FileUpload需要RequestContext (除非有一種簡單的方法將HttpRequest轉換為RequestContext ,我忽略了。)

你可以使用Commons FileUpload解析你的String,將它包裝在一個實現'org.apache.commons.fileupload.UploadContext'的類中,如下所示。

我建議將HttpRequest包裝在您建議的備用解決方案中,但原因有兩個。 首先,使用String意味着整個多部分POST主體(包括文件內容)需要適合內存。 包裝HttpRequest將允許您流式傳輸,一次只有一個小內存緩沖區。 其次,如果沒有HttpRequest,你需要嗅出多部分邊界,這通常位於“Content-type”標題中(參見RFC1867 )。

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;

public class MultiPartStringParser implements org.apache.commons.fileupload.UploadContext {

    public static void main(String[] args) throws Exception {
        String s = new String(Files.readAllBytes(Paths.get(args[0])));
        MultiPartStringParser p = new MultiPartStringParser(s);
        for (String key : p.parameters.keySet()) {
            System.out.println(key + "=" + p.parameters.get(key));
        }
    }

    private String postBody;
    private String boundary;
    private Map<String, String> parameters = new HashMap<String, String>();

    public MultiPartStringParser(String postBody) throws Exception {
        this.postBody = postBody;
        // Sniff out the multpart boundary.
        this.boundary = postBody.substring(2, postBody.indexOf('\n')).trim();
        // Parse out the parameters.
        final FileItemFactory factory = new DiskFileItemFactory();
        FileUpload upload = new FileUpload(factory);
        List<FileItem> fileItems = upload.parseRequest(this);
        for (FileItem fileItem: fileItems) {
            if (fileItem.isFormField()){
                parameters.put(fileItem.getFieldName(), fileItem.getString());
            } // else it is an uploaded file
        }
    }

    public Map<String,String> getParameters() {
        return parameters;
    }

    // The methods below here are to implement the UploadContext interface.
    @Override
    public String getCharacterEncoding() {
        return "UTF-8"; // You should know the actual encoding.
    }

    // This is the deprecated method from RequestContext that unnecessarily
    // limits the length of the content to ~2GB by returning an int. 
    @Override
    public int getContentLength() {
        return -1; // Don't use this
    }

    @Override
    public String getContentType() {
        // Use the boundary that was sniffed out above.
        return "multipart/form-data, boundary=" + this.boundary;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return new ByteArrayInputStream(postBody.getBytes());
    }

    @Override
    public long contentLength() {
        return postBody.length();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM