1. 程式人生 > >Android-日常遭遇-檔案上傳MIME協議

Android-日常遭遇-檔案上傳MIME協議

寫上傳檔案的時候,需要產生part才能讓檔案上傳成功,

而android原生並沒有提供這樣的方法,需要自己寫.首先看下mime協議

MIME Multipart Media Encapsulation, Type: multipart/form-data, Boundary: "AF+hwZxkNq38nq6w4liUUA"
    [Type: multipart/form-data]
    First boundary: --AF+hwZxkNq38nq6w4liUUA==\r\n
    Encapsulated multipart part: 
        Data (102 bytes)
            Data: 2d2d41462b68775a786b4e7133386e713677346c69555541...
            [Length: 102]
    Boundary: \r\n--AF+hwZxkNq38nq6w4liUUA==\r\n
    Encapsulated multipart part:  (application/octet-stream)
        Content-Disposition: form-data; name="userfile"; filename="aaa.mp4"\r\n
        Content-Type: application/octet-stream\r\n\r\n
        Data (2003015 bytes)
            Data: 000000206674797069736f6d0000020069736f6d69736f32...
            [Length: 2003015]
    Boundary: \r\n--AF+hwZxkNq38nq6w4liUUA==--\r\n
    Encapsulated multipart part: 

可以看出,是由

--邊界碼

Content-Disposition-key

value

--邊界碼

...

--邊界碼--

結束

由此可以模仿出

 


    private void postFile(PostFormBody body) throws IOException {
        // 說明有檔案
        // 邊界標識 隨機生成
        Random random      = new Random();
        byte[] randomBytes = new byte[16];
        random.nextBytes(randomBytes);
        String boundary = Base64.encodeToString(randomBytes, Base64.NO_WRAP);
        String prefix   = "--";
        String lineEnd  = "\r\n";
        currentCallRequest.getConnection().setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
        OutputStream     outputStream = currentCallRequest.getConnection().getOutputStream();
        DataOutputStream out          = putParams(body, boundary, prefix, lineEnd, outputStream);
        putFile(body, boundary, prefix, lineEnd, out);
        out.flush();
        out.close();
    }

    @NonNull
    private DataOutputStream putParams(PostFormBody body, String boundary, String prefix, String lineEnd, OutputStream outputStream) throws IOException {
        DataOutputStream    out      = new DataOutputStream(outputStream);
        Map<String, String> queryMap = body.params;
        if (queryMap != null && !queryMap.isEmpty()) {
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, String> entry : queryMap.entrySet()) {
                String key   = entry.getKey();
                String value = entry.getValue();
                sb.append(prefix).append(boundary).append(lineEnd);
                out.write(sb.toString().getBytes());
                sb.append("Content-Disposition")
                        .append(": ")
                        .append("form-data")
                        .append("; name=\"")
                        .append(key)
                        .append("\"")
                        .append(lineEnd);
                sb.append("Content-Length")
                        .append(": ")
                        .append(value.length())
                        .append(lineEnd)
                        .append(lineEnd);
                sb.append(value).append(lineEnd);

            }
            out.write(sb.toString().getBytes());
            out.flush();
        }
        return out;
    }

    private void putFile(PostFormBody body, String boundary, String prefix, String lineEnd, DataOutputStream out) throws IOException {
        StringBuilder sb = new StringBuilder();
        sb.append(prefix).append(boundary).append(lineEnd);
        sb.append(CONTENT_DISPOSITION)
                .append(": ")
                .append("form-data")
                .append("; name=\"")
                .append(body.keyFile)
                .append("\"; filename=\"")
                .append(body.mFile.getName())
                .append("\"")
                .append(lineEnd);
        sb.append( + "Content-Type: application/octet-stream").append(lineEnd);
        sb.append(lineEnd);
        out.write(sb.toString().getBytes());
        out.flush();
        InputStream input = new FileInputStream(body.mFile);
        byte[]      bytes = new byte[1024];
        int         len   = 0;
        while ((len = input.read(bytes)) != -1) {
            out.write(bytes, 0, len);
        }
        out.write(lineEnd.getBytes());
        out.flush();
        byte[] endData = (prefix + boundary + prefix + lineEnd).getBytes();
        out.write(endData);
        out.flush();
        input.close();
    }

PostFormBody

    public Map<String, String> params;
    public String              keyFile;
    public File                mFile;

    private PostFormBody(Builder builder) {
        params = builder.params;
        keyFile = builder.keyFile;
        mFile = builder.mFile;
    }

這裡有一點需要注意

currentCallRequest.getConnection().setRequestProperty(CONTENT_TYPE, TYPE_FORM_DATA_NO_CHARSET + "; boundary=" + boundary);

這邊是不能有引號以及其他符號,如果有其他符號會導致檔案上傳,將資料疊加到一起.導致上傳失敗

如果是正常,則會讓協議成功

詳細封裝可以看我的github

EHttp