首先,簡單介紹下Http請求中Content-Type類型
- 類型格式:type/subtype(;parameter)? type
- 主類型,任意的字符串,如text,如果是*號代表所有;
- subtype 子類型,任意的字符串,如html,如果是*號代表所有;
- parameter 可選,一些參數,如Accept請求頭的q參數, Content-Type的 charset參數。
例如: Content-Type: text/html;charset=utf-8;
常見的媒體格式類型如下:
- text/html : HTML格式
- text/plain :純文本格式
- text/xml : XML格式
- image/gif :gif圖片格式
- image/jpeg :jpg圖片格式
- image/png:png圖片格式
以application開頭的媒體格式類型:
- application/xhtml+xml :XHTML格式
- application/xml : XML數據格式
- application/atom+xml :Atom XML聚合格式
- application/json : JSON數據格式
- application/pdf :pdf格式
- application/msword : Word文檔格式
- application/octet-stream : 二進制流數據(如常見的文件下載)
- application/x-www-form-urlencoded : <form encType=””>中默認的encType,當form表單請求為get時,數據被編碼為key/value格式(name1=value1&name2=value2…),然后把這個字串append到url后面,用?分割,加載這個新的url發送到服務器(表單默認的提交數據的格式);當請求為post時,瀏覽器把form數據封裝到http body中,然后發送到server。(form的enctype屬性為編碼方式,常用有兩種:application/x-www-form-urlencoded和multipart/form-data,默認為application/x-www-form-urlencoded。)
另外一種常見的媒體格式是上傳文件之時使用的:
- multipart/form-data : 需要在表單中進行文件上傳時,就需要使用該格式
以上就是我們在日常的開發中,經常會用到的若干content-type的內容格式。
最近項目開發對接接口,那邊發送http post請求(
已知是xml數據,類似 <?xml version="1.0" encoding="GBK"?><Advpay><PubInfo><ReturnCode>0000</ReturnCode>**其他節點略**</PubInfo</Advpay>),
抓包顯示,"Content-Type" 是 "application/x-www-form-urlencoded;charset=GBK",
在body里用如下方式獲取數據:(該方式獲取不到數據)
public String parserRequest() { HttpServletRequest request = ServletActionContext.getRequest(); StringBuffer sb = null; InputStream in = null; BufferedReader br = null; try { in = request.getInputStream(); br = new BufferedReader(new InputStreamReader(in, "utf-8")); sb = new StringBuffer(); String s = ""; while ((s = br.readLine()) != null) { sb.append(s); } } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage(), e); } finally { try { if (br != null) { br.close(); } if (in != null) { in.close(); } } catch (Exception e) { e.printStackTrace(); } } String xml = sb.toString(); if (xml != null && !"".equals(xml)) { logger.info("報文response xml = " + xml); } return xml; }
這種方式可以:(覺得很怪。。。想着一般post請求,都body體讀取流數據
"Content-Type" = "application/x-www-form-urlencoded 這種格式要特別注意)
public String parserRequest() { HttpServletRequest request = ServletActionContext.getRequest(); String reqXml = null; try { Map<String, String[]> map = request.getParameterMap(); StringBuffer xmlBuf = new StringBuffer(); for (Map.Entry<String, String[]> m : map.entrySet()) { logger.info("返回的報文 key=" + m.getKey() + " Value[0]=" + m.getValue()[0]);
//打印出來的key=<?xml version value[0]="1.0" encoding="GBK"?><Advpay><PubInfo><ReturnCode>0000</ReturnCode>**其他節點略**</PubInfo</Advpay>
xmlBuf.append(m.getKey()); xmlBuf.append("="); xmlBuf.append(m.getValue()[0]); } reqXml = xmlBuf.toString(); } catch (Exception e) { logger.error("Exception" + e.getMessage(), e); } if (reqXml != null && !"".equals(reqXml)) { logger.info("報文response reqXml = " + reqXml); } return reqXml; }
原因如下:
在servlet規范3.1.1節里
1. The request is an HTTP or HTTPS request.
2. The HTTP method is POST.
3. The content type is application/x-www-form-urlencoded.
4. The servlet has made an initial call of any of the getParameter family of methods on the request object.
If the conditions are met, post form data will no longer be available for reading directly from the request object’s input stream.
在tomcat的Request.parseParameters方法里,對於application/x-www-form-urlencoded是有做判斷的,對這種編碼會去解析body里的數據,填充到parameters里,所以后續想再通過流的方式讀取body是讀不到的(除非你沒有觸發過getParameter相關的方法)。
tomcat源碼。。。待續。。。。。。。。。。。。。
另外,看了下 org.apache.commons.httpclient.HttpClient 的源碼 ,設置body體數據編碼格式,
postMethod.setRequestEntity(new StringRequestEntity(body,contentType, charSet));
當"Content-Type" = "application/x-www-form-urlencoded;charset=GBK"
charSet="UTF-8" 兩個參數都傳入時,到底用哪個編碼?
由源碼看來,以第二個參數 charSet 為准。

未完待續。。。。。。
