在常見業務開發中,POST請求經常在這些地方使用:前端表單提交時、調用接口代碼時和使用Postman測試接口時。咱們下面來一一瞭解:php
表單代碼:html
<form action="http://localhost:8888/task/" method="POST"> First name: <input type="text" name="firstName" value="Mickey&"><br> Last name: <input type="text" name="lastName" value="Mouse "><br> <input type="submit" value="提交"> </form>
經過測試發現能夠正常訪問接口,在Chrome的開發者工具中能夠看出,表單上傳編碼格式爲application/x-www-form-urlencoded
(Request Headers中),參數的格式爲key=value&key=value
。前端
咱們能夠看出,服務器知道參數用符號&
間隔,若是參數值中須要&
,則必須對其進行編碼。編碼格式就是application/x-www-form-urlencoded
(將鍵值對的參數用&鏈接起來,若是有空格,將空格轉換爲+
加號;有特殊符號,將特殊符號轉換爲ASCII HEX
值)。web
application/x-www-form-urlencoded
是瀏覽器默認的編碼格式。對於Get請求,是將參數轉換?key=value&key=value
格式,鏈接到url後spring
ps:能夠在這個網址測試表單:http://www.runoob.com/try/try.php?filename=tryhtml_form_submitjson
那麼當服務器使用multipart/form-data
接收POST請求時,服務器怎麼知道每一個參數的開始位置和結束位置呢?瀏覽器
<form action="http://localhost:8888/task/" method="POST" enctype="multipart/form-data"> First name: <input type="text" name="firstName" value="Mickey&"><br> Last name: <input type="text" name="lastName" value="Mouse "><br> <input type="submit" value="提交"> </form>
咱們在開發者工具中能夠看出multipart/form-data
不會對參數編碼,使用的boundary
(分割線),至關於&
,boundary
的值是----Web**AJv3
。服務器
上傳文件也要指定編碼格式爲multipart/form-data
。app
<form action="http://localhost:8888/testFile" enctype="multipart/form-data" method="POST"> <input type="file" name="file"> <input type="submit" value="提交"> </form>
若是是SpringMVC項目,要服務器能接受multipart/form-data
類型參數,還要在spring上下文配置如下內容,SpringBoot項目則不須要。工具
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="utf-8"></property> </bean>
咱們能夠經過FormData對象模擬表單提交,用原始的XMLHttpRequest來發送數據,讓咱們能夠在Chrome開發工具中查看到具體格式:
<form id="form"> First name: <input type="text" name="firstName" value="Mickey"><br> Last name: <input type="text" name="lastName" value="Mouse"><br> <input type="file" name="file"><br> </form> <button onclick="submitForm()">提交</button> <script> function submitForm() { var formElement = document.getElementById("form"); var xhr = new XMLHttpRequest(); xhr.open("POST", "/task/testFile"); xhr.send(new FormData(formElement)); } </script>
格式以下:
一、在代碼中使用application/x-www-form-urlencoded
編碼格式設置Request屬性調用接口,能夠以下實現:
private static String doPost(String strUrl, String content) { String result = ""; try { URL url = new URL(strUrl); //經過調用url.openConnection()來得到一個新的URLConnection對象,而且將其結果強制轉換爲HttpURLConnection. HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("POST"); //設置鏈接的超時值爲30000毫秒,超時將拋出SocketTimeoutException異常 urlConnection.setConnectTimeout(30000); //設置讀取的超時值爲30000毫秒,超時將拋出SocketTimeoutException異常 urlConnection.setReadTimeout(30000); //將url鏈接用於輸出,這樣才能使用getOutputStream()。getOutputStream()返回的輸出流用於傳輸數據 urlConnection.setDoOutput(true); //設置通用請求屬性爲默認瀏覽器編碼類型 urlConnection.setRequestProperty("content-type", "application/x-www-form-urlencoded"); //getOutputStream()返回的輸出流,用於寫入參數數據。 OutputStream outputStream = urlConnection.getOutputStream(); outputStream.write(content.getBytes()); outputStream.flush(); outputStream.close(); //此時將調用接口方法。getInputStream()返回的輸入流能夠讀取返回的數據。 InputStream inputStream = urlConnection.getInputStream(); byte[] data = new byte[1024]; StringBuilder sb = new StringBuilder(); //inputStream每次就會將讀取1024個byte到data中,當inputSteam中沒有數據時,inputStream.read(data)值爲-1 while (inputStream.read(data) != -1) { String s = new String(data, Charset.forName("utf-8")); sb.append(s); } result = sb.toString(); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } return result; } public static void main(String[] args) { String str = doPost("http://localhost:8888/task/", "firstName=Mickey%26&lastName=Mouse "); System.out.println(str); }
二、在代碼中使用multipart/form-data
編碼格式設置Request屬性調用接口時,其中boundary
的值能夠在設置Content-Type時指定,讓服務器知道如何拆分它接受的參數。經過如下代碼的調用接口:
private static String doPost(String strUrl, Map<String, String> params, String boundary) { String result = ""; try { URL url = new URL(strUrl); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("POST"); urlConnection.setConnectTimeout(30000); urlConnection.setReadTimeout(30000); urlConnection.setDoOutput(true); //設置通用請求屬性爲multipart/form-data urlConnection.setRequestProperty("content-type", "multipart/form-data;boundary=" + boundary); DataOutputStream dataOutputStream = new DataOutputStream(urlConnection.getOutputStream()); for (String key : params.keySet()) { String value = params.get(key); //注意!此處是\r(回車:將當前位置移到本行開頭)、\n(換行:將當前位置移到下行開頭)要一塊兒使用 dataOutputStream.writeBytes("--" + boundary + "\r\n"); dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + encode(key) + "\"\r\n"); dataOutputStream.writeBytes("\r\n"); dataOutputStream.writeBytes(encode(value) + "\r\n"); } //最後一個分隔符的結尾後面要跟"--" dataOutputStream.writeBytes("--" + boundary + "--"); dataOutputStream.flush(); dataOutputStream.close(); InputStream inputStream = urlConnection.getInputStream(); byte[] data = new byte[1024]; StringBuilder sb = new StringBuilder(); while (inputStream.read(data) != -1) { String s = new String(data, Charset.forName("utf-8")); sb.append(s); } result = sb.toString(); inputStream.close(); } catch (Exception e) { e.printStackTrace(); } return result; } private static String encode(String value) throws UnsupportedEncodingException { return URLEncoder.encode(value, "UTF-8"); } public static void main(String[] args) { Map<String, String> params = new HashMap<>(); params.put("firstName", "Mickey"); params.put("lastName", "Mouse"); //自定義boundary,有兩個要求:使用不會出如今發送到服務器的HTTP數據中的值;並在請求消息中的分割位置都使用相同的值 String boundary = "abcdefg"; String str = doPost("http://localhost:8888/testFile", params, boundary); System.out.println(str); }
經過debug,能夠看出dataOutputStream的值以下:
當切換爲x-www-form-urlencoded
時,Headers會自動添加Content-Type:application/x-www-form-urlencoded
當請求Send後,此時點Code
,能夠查看到和Chrome開發工具中(Request Headers處的Content-Type和Form Data)同樣的數據
至關於html表單請求,value可爲Text或文件。
能夠不用手動指定編碼格式,也能夠指定編碼爲multipart/form-data
劃線處的分割線應該是被省略了。
能夠更改左上角的類型,來查看相應的Headers代碼,常見的是下面三種:
Java OK HTTP:
JavaScript Jquery AJAX:
JavaScript XHR:
POST請求的兩種編碼格式:application/x-www-urlencoded
是瀏覽器默認的編碼格式,用於鍵值對參數,參數之間用&
間隔;multipart/form-data
經常使用於文件等二進制,也可用於鍵值對參數,最後鏈接成一串字符傳輸(參考Java OK HTTP)。除了這兩個編碼格式,還有application/json
也常常使用。
@RequestMapping("/task") public class TaskController { @RequestMapping("/") public String index(String firstName, String lastName) { return firstName + lastName; } @RequestMapping("/testFile") public String testFile(String firstName, String lastName, MultipartFile file) { String result = firstName + lastName; if (file != null) { result += (file.getOriginalFilename() != null) ? file.getOriginalFilename() : ""; } return result; } }
HTML <form> 標籤的 enctype 屬性:http://www.w3school.com.cn/tags/att_form_enctype.asp HttpUrlConnection 基礎使用:https://www.cnblogs.com/libertycode/p/5979260.html SpringMvc接收multipart/form-data 傳輸的數據 及 PostMan各種數據類型的區別:https://www.cnblogs.com/ifindu-san/p/8251370.html#undefined What is the boundary in multipart/form-data?:https://stackoverflow.com/questions/3508338/what-is-t