Http multipart/form-data多參數Post方式上傳數據


最近,工作中遇到需要使用java實現http發送get、post請求,簡單的之前經常用到,但是這次遇到了上傳文件的情況,之前也沒深入了解過上傳文件的實現,這次才知道通過post接口也可以,是否還有其他方式我還不知道。

下面來說具體問題,就是要通過接口post方式上傳一個excel文件,另外還有其他2個參數,當然,對我來說就是這個文件不知道怎么傳,后來通過網上的幾篇文章了解到整個文件可以做為一個參數,通過chrome或抓包工具可以看到參數情況如下所示:

--(boundary的任意字符串)**********
Content-Disposition: form-data; name="postKey"

postValue
--(boundary的任意字符串)**********
Content-Disposition: form-data; name="postKey"; filename="file.getName()"
Content-Type: image/png; charset=utf-8
(文件的二進制數據)
--(boundary的任意字符串)**********--

這個是引用網上那篇文章的,注意這里只有2個參數,第一個是普通參數,參數名師postKey,參數值是postValue。第二個參數則是要上傳的文件,此處是一張圖片,當然也可以是txt,excel都可以。這是chrome開發者工具中查看到的樣子,注意這個(文件的二進制數據),在chrome里是看不到的,fiddler可以看到是一堆亂碼,也就是說把文件轉換成二進制字符串了。然后運行了一下,發現還是報錯,報400錯誤,其實這應該指的還是參數格式不對,也就是我拼的這個參數的串格式還是有問題,但此時,我卻猜測可能是https的問題,因為我需要調用的接口是https的,之前也是一直在搞http的,沒有弄過https的,所以又是一番研究https,並且還得支持上傳文件和多參數。后來,按照網上文章的說法引用了幾個支持https的類,覺得應該https沒問題了,但還是報400錯誤,於是猜測問題肯定出在字符串的格式上,最后,發現connection.SetRequestProperty時,設置的邊界字符串與實際拼參數是的邊界有差異,多了兩個中划線,去掉后就post成功了,然后又回過頭來看到底和https有沒有關系,注釋掉了所有關於https的代碼,發現一樣可以post成功,也就是說,至少我這接口雖然是要求https的,但java實現時可以不用考慮https,http就可以。下面貼出代碼,注釋掉的部分就是與https相關的

    public static ResponseVo importForBatchAddDetailsPost(String requestUrl,String promoId,String operator, String filePath) {
        File file=new File(filePath);
        ResponseVo result = new ResponseVo();
        JSONObject json = new JSONObject();
        String BOUNDARY = "------WebKitFormBoundaryAl9CIOBJ1jfQWTl8";
        URL url;

        try {
            url = new URL(requestUrl);
            //SSLContext sc=SSLContext.getInstance("SSL");
            //sc.init(null,new TrustManager[] {new MyX509TrustManager()},new java.security.SecureRandom());
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            //urlConnection.setSSLSocketFactory(sc.getSocketFactory());
            //urlConnection.setHostnameVerifier(new TrustAnyHostnameVerifier());
            urlConnection.setUseCaches(false);
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setRequestProperty("Connection","Keep-Alive");
            urlConnection.setRequestProperty("Uuser-Agent","Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36");
            urlConnection.setRequestProperty("Charset","UTF-8");
            urlConnection.setRequestProperty("Content-Type","multipart/form-data; boundary=" + "----WebKitFormBoundaryAl9CIOBJ1jfQWTl8");
            urlConnection.connect();
            StringBuilder contentBody1 = new StringBuilder();
            StringBuilder contentBody2 = new StringBuilder();
            String boundary = BOUNDARY+ "\r\n";
            DataOutputStream out =new DataOutputStream(urlConnection.getOutputStream());
            byte[] end_data=("------WebKitFormBoundaryAl9CIOBJ1jfQWTl8--".getBytes());
            if (file != null) {
                //第一部分參數:excel文件
                contentBody1.append(boundary);
                contentBody1.append("Content-Disposition: form-data; name=\"file\"; filename=\"ActImportHouseTemplate.xlsx\""+"\r\n");
                contentBody1.append("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"+"\r\n");
                contentBody1.append("\r\n");

                out.write(contentBody1.toString().getBytes());
                //讀取excel文件
                DataInputStream dis = new DataInputStream(new FileInputStream(file));
                int bytes = 0;
                byte[] bufferOut = new byte[(int) file.length()];
                bytes = dis.read(bufferOut);
                out.write(bufferOut, 0, bytes);
                out.write("\r\n".getBytes());
                dis.close();
                //第二部分參數:其他參數promoId,operator
                contentBody2.append(boundary);
                contentBody2.append("Content-Disposition: form-data; name=\"promoId\""+ "\r\n");
                contentBody2.append("\r\n");
                contentBody2.append(promoId+ "\r\n");
                contentBody2.append(boundary);
                contentBody2.append("Content-Disposition: form-data; name=\"operator\""+ "\r\n");
                contentBody2.append("\r\n");
                contentBody2.append(operator+ "\r\n");

                out.write(contentBody2.toString().getBytes());
                out.write(end_data);
                out.flush();

                //從服務器獲得回答的內容
                InputStream inputStream=urlConnection.getInputStream();
                InputStreamReader reader=new InputStreamReader(inputStream);
                BufferedReader in=new BufferedReader(reader);
                String strLine = "";
                String strResponse = "";
                while ((strLine = in.readLine()) != null) {
                    strResponse += strLine + "\n";
                    json = JSON.parseObject(strResponse);
                }
                    result.setJson(json);
                    out.close();

            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //catch (NoSuchAlgorithmException e){}
        //catch (NoSuchProviderException e){}
        //catch (KeyManagementException e){}
        return result;
    }

另外貼出https需要用到的兩個類

public class MyX509TrustManager implements X509TrustManager{

    public MyX509TrustManager(){}
    @Override
    public void checkClientTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {
        // TODO Auto-generated method stub

    }

    @Override
    public void checkServerTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {
        // TODO Auto-generated method stub

    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        // TODO Auto-generated method stub
        return null;
    }

    public static SSLSocketFactory getSSFactory() throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException{
        TrustManager[] tm = { new MyX509TrustManager()};
        SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
        sslContext.init(null, tm, new java.security.SecureRandom());
        SSLSocketFactory ssf = sslContext.getSocketFactory();
        return  ssf;
    }

}
public class TrustAnyHostnameVerifier implements HostnameVerifier {
    public boolean verify(String hostname, SSLSession session){
        return true;
    }
}

具體這兩個類是否好使,為什么這么寫,我也不確定,如果只是簡單post一個https接口,可以參照下面這個文章:https://www.cnblogs.com/lichmama/p/6780298.html   其中用到的bing圖片地址已經過期,可以用這個接口查找:https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1,最后拼出來的圖片地址如:https://cn.bing.com/az/hprichbg/rb/ComicFans_ZH-CN10352835982_1920x1080.jpg

 

綜上,總結如下:

1、java實現的http請求可以有很多種,除了常見的get、post,還可以上傳文件

2、上傳文件除了通過接口上傳,應該還有其他方式

3、java實現http和https請求應該大多數是通用的

4、http上傳文件,一定要注意參數字符串的拼接格式,主要有以下幾點:

   (1)邊界的字符串是隨機生成的,只要保證每個邊界一樣即可,注意只有最后一行邊界是在末尾多出兩個中划線的

   (2)參數中的換行應該與抓包中的一致,據說是由嚴格要求,我也沒試過不一致的情況

   (3)參數的順序是否無關緊要,這個我也沒試過

 

最后貼出兩篇參考文章的地址:

java實現https請求
https://www.cnblogs.com/lichmama/p/6780298.html
Http multipart/form-data多參數Post方式上傳數據
https://blog.csdn.net/futianjie_china/article/details/53523814


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM