最近,工做中遇到須要使用java實現http發送get、post請求,簡單的以前常常用到,可是此次遇到了上傳文件的狀況,以前也沒深刻了解過上傳文件的實現,此次才知道經過post接口也能夠,是否還有其餘方式我還不知道。html
下面來講具體問題,就是要經過接口post方式上傳一個excel文件,另外還有其餘2個參數,固然,對我來講就是這個文件不知道怎麼傳,後來經過網上的幾篇文章瞭解到整個文件能夠作爲一個參數,經過chrome或抓包工具能夠看到參數狀況以下所示:java
--(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相關的chrome
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須要用到的兩個類json
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服務器
綜上,總結以下:session
一、java實現的http請求能夠有不少種,除了常見的get、post,還能夠上傳文件app
二、上傳文件除了經過接口上傳,應該還有其餘方式dom
三、java實現http和https請求應該大多數是通用的ide
四、http上傳文件,必定要注意參數字符串的拼接格式,主要有如下幾點:工具
(1)邊界的字符串是隨機生成的,只要保證每一個邊界同樣便可,注意只有最後一行邊界是在末尾多出兩個中劃線的
(2)參數中的換行應該與抓包中的一致,聽說是由嚴格要求,我也沒試過不一致的狀況
(3)參數的順序是否可有可無,這個我也沒試過
最後貼出兩篇參考文章的地址:
java實現https請求https://www.cnblogs.com/lichmama/p/6780298.htmlHttp multipart/form-data多參數Post方式上傳數據https://blog.csdn.net/futianjie_china/article/details/53523814