之前在基於C#開發彩信用最原始的StringBuilder拼接字符串方式處理過Multipart。現在在做一個項目的時候,由於之前的技術路線都是使用Jersey處理Http這塊,為了保持技術路線一致,研究了一下如何使用Jersey處理Http協議中的Multipart。
那么Http協議中的Multipart是個什么東東?下面是摘抄http協議1.1的一段話:
在multipart entity(多部分實體)的例子中,一個或多個不同的數據集合並在一個單一的body(體)中,一個"multipart"(多部分)類型 field的(域)必須出現在實體的header(頭域)。body(體)必須包括一個或多個body part(體部分),每一個位於boundary(邊界)定界符線之前,最后一個則跟着一個結束邊界定界符線。在它的邊界定界符線后,每一個體部分由頭域、空行、體組成。
上面的描述寫的有點拗口,簡單的理解可以為:一個post的請求,可以根據一定規范去定義多個部分;
下面用移動網狀網協議(其實就是一個請求中包括2個獨立的xml內容,一個head的xml,一個body的xml)去舉例說明如何利用Jersey處理Multipart,主要代碼如下(開始的時候server端接收的代碼死活不知道如何寫也沒查到別人怎么寫的,后來一生氣,反編譯jersey-multipart-1.0.3.1.jar包的代碼看了下,才明白):
private static WebResource webResource = client.resource("http://xxx.xx.xx:xxx"); public static final String HeadFieldName = "xmlhead"; public static final String BodyFieldName = "xmlbody"; // Client發送代碼 public static String post(String head, String body) throws BusinessException { FormDataMultiPart multiPart = new FormDataMultiPart(); multiPart.field(RequestField.HeadFieldName, head, MediaType.MULTIPART_FORM_DATA_TYPE); multiPart.field(RequestField.BodyFieldName, body, MediaType.MULTIPART_FORM_DATA_TYPE); return webResource.type("multipart/form-data").post(String.class, multiPart); } // Server端接收代碼 @POST @Produces({MediaType.APPLICATION_XML, MediaType.MULTIPART_FORM_DATA}) @Consumes({MediaType.APPLICATION_XML, MediaType.MULTIPART_FORM_DATA}) public String service(FormDataMultiPart multiPart) throws Exception{ if(multiPart == null){ if(_logger.isErrorEnabled()){ _logger.error("the request FormDataMultiPart is null"); } throw new Exception("the request FormDataMultiPart is null"); } List<RequestField> requestFields = new ArrayList<RequestField>(); for(BodyPart bodyPart : multiPart.getBodyParts()){ String fieldName = ((FormDataBodyPart)bodyPart).getName().trim(); if(fieldName.equalsIgnoreCase(RequestField.HeadFieldName)){ requestFields.add(new RequestField(fieldName, bodyPart.getEntityAs(String.class))); } else if(fieldName.equalsIgnoreCase(RequestField.BodyFieldName)){ requestFields.add(new RequestField(fieldName, bodyPart.getEntityAs(String.class))); } else{ if(_logger.isWarnEnabled()){ _logger.warn("invalid fieldName:" + fieldName + ",originXml:" + bodyPart.getEntityAs(String.class)); } } } ..... }
用工具抓包的實際post報文:
POST /ba/resources/bossServer HTTP/1.1 Content-Type: multipart/form-data;boundary=Boundary_1_30911772_1367997277472 MIME-Version: 1.0 User-Agent: Java/1.6.0_10-rc2 Host: 192.168.245.18:8082 Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive Content-Length: 1600 --Boundary_1_30911772_1367997277472 Content-Disposition: form-data;name="xmlhead" Content-Type: multipart/form-data <?xml version="1.0" encoding="UTF-8"?> <InterBOSS> <Version>0100</Version> <TestFlag>0</TestFlag> <BIPType> <BIPCode>BIP2B543</BIPCode> <ActivityCode>T2001543</ActivityCode> <ActionCode>0</ActionCode> </BIPType> <RoutingInfo> <OrigDomain>IMPS</OrigDomain> <RouteType>01</RouteType> <Routing> <HomeDomain>BOSS</HomeDomain> <RouteValue>13810494631</RouteValue> </Routing> </RoutingInfo> <TransInfo> <SessionID>2013050815143783928824</SessionID> <TransIDO>2013050815143783928824</TransIDO> <TransIDOTime>20130508151437</TransIDOTime> </TransInfo> </InterBOSS> --Boundary_1_30911772_1367997277472 Content-Disposition: form-data;name="xmlbody" Content-Type: multipart/form-data <?xml version="1.0" encoding="UTF-8"?> <InterBOSS> <SvcCont><![CDATA[<subscribeServiceReq> <msgTransactionID>210001BIP2B543130508151437477294</msgTransactionID> <subscribeServInfo> <oprTime>20130508151436</oprTime> <actionID>06</actionID> <effTime>20130508151437</effTime> <expireTime>30000101000000</expireTime> <feeUser_ID>13810494631</feeUser_ID> <destUser_ID>13810494631</destUser_ID> <actionReasonID>1</actionReasonID> <servType>210001</servType> <subServType>FXCJHY</subServType> <SPID>901508</SPID> <SPServID>FXCJHY</SPServID> <accessMode>01</accessMode> <feeType>2</feeType> </subscribeServInfo> </subscribeServiceReq>]]></SvcCont> </InterBOSS> --Boundary_1_30911772_1367997277472--