標籤:style blog http io color os ar java for
struts2: 玩轉 rest-plugin 一文中,學習了用struts2開發restful service的方法,發現用c#以post方式調用時各種報錯,但java、ajax,包括firefox 的rest client外掛程式測試也無問題。
先給出rest service中的這個方法:
1 // POST /orders 2 public HttpHeaders create() throws IOException, ServletException { 3 ordersService.doSave(model); 4 HttpServletResponse response = ServletActionContext.getResponse(); 5 HttpServletRequest request = ServletActionContext.getRequest(); 6 String ContentType = request.getHeader("Content-Type").toLowerCase(); 7 if (ContentType.startsWith("application/xml")) { // 返回xml視圖 8 response.sendRedirect("orders/" + model.getId() + ".xml"); 9 } else if (ContentType.startsWith("application/json")) { // 返回json視圖10 response.sendRedirect("orders/" + model.getId() + ".json");11 } else {// 返回xhtml整頁模式12 response.sendRedirect("orders/");13 }14 return null;15 }View Code
代碼不複雜,post一段String過來(xml/json/html格式均可),自動對應成Order對象的執行個體model,然後根據請求HttpHeader中的Content-Type,如果是xml(application/xml),則返回model對應的xml,如果是json(application/json),則返回model對應的json,其它則返回頁面
c#的調用代碼:
1 static string PostDataByWebClient(String postUrl, String paramData, String mediaType) 2 { 3 String result = String.Empty; 4 try 5 { 6 byte[] postData = Encoding.UTF8.GetBytes(paramData); 7 WebClient webClient = new WebClient(); 8 webClient.Headers.Add("Content-Type", mediaType); 9 byte[] responseData = webClient.UploadData(new Uri(postUrl), "POST", postData);10 result = Encoding.UTF8.GetString(responseData);11 }12 catch (Exception e)13 {14 Console.WriteLine(e);15 result = e.Message;16 }17 return result;18 }19 20 static string PostDataByWebRequest(string postUrl, string paramData, String mediaType)21 {22 string result = string.Empty;23 Stream newStream = null;24 StreamReader sr = null;25 HttpWebResponse response = null;26 try27 {28 byte[] byteArray = Encoding.UTF8.GetBytes(paramData);29 HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(new Uri(postUrl));30 webReq.Method = "POST";31 webReq.ContentType = mediaType;32 webReq.ContentLength = byteArray.Length;33 newStream = webReq.GetRequestStream();34 newStream.Write(byteArray, 0, byteArray.Length);35 response = (HttpWebResponse)webReq.GetResponse();36 sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);37 result = sr.ReadToEnd();38 }39 catch (Exception ex)40 {41 Console.WriteLine(ex);42 result = ex.Message;43 }44 finally45 {46 if (sr != null)47 {48 sr.Close();49 }50 if (response != null)51 {52 response.Close();53 }54 if (newStream != null)55 {56 newStream.Close();57 }58 }59 return result;60 }View Code
這二種常用的調用方式,居然全跪了,返回的結果是一堆java異常:
java.lang.NullPointerException
at org.apache.struts2.convention.ConventionUnknownHandler.handleUnknownActionMethod(ConventionUnknownHandler.java:423)
at com.opensymphony.xwork2.DefaultUnknownHandlerManager.handleUnknownMethod(DefaultUnknownHandlerManager.java:96)
...
無奈百度了一圈,發現還有另一種方法,利用TcpClient調用
1 static string PostDataByTcpClient(string postUrl, string paramData, String mediaType) 2 { 3 String result = String.Empty; 4 TcpClient clientSocket = null; 5 Stream readStream = null; 6 try 7 { 8 clientSocket = new TcpClient(); 9 Uri URI = new Uri(postUrl);10 clientSocket.Connect(URI.Host, URI.Port);11 StringBuilder RequestHeaders = new StringBuilder();//用來儲存HTML協議頭部資訊12 RequestHeaders.AppendFormat("{0} {1} HTTP/1.1\r\n", "POST", URI.PathAndQuery);13 RequestHeaders.AppendFormat("Connection:close\r\n");14 RequestHeaders.AppendFormat("Host:{0}\r\n", URI.Host);15 RequestHeaders.AppendFormat("Content-Type:{0}\r\n",mediaType);16 RequestHeaders.AppendFormat("\r\n");17 RequestHeaders.Append(paramData + "\r\n");18 Encoding encoding = Encoding.UTF8;19 byte[] request = encoding.GetBytes(RequestHeaders.ToString());20 clientSocket.Client.Send(request);21 readStream = clientSocket.GetStream();22 StreamReader sr = new StreamReader(readStream, Encoding.UTF8);23 result = sr.ReadToEnd();24 }25 catch (Exception e)26 {27 Console.WriteLine(e);28 result = e.Message;29 }30 finally31 {32 if (readStream != null)33 {34 readStream.Close();35 }36 if (clientSocket != null)37 {38 clientSocket.Close();39 }40 }41 return result;42 }View Code
總算調用成功了,但是由於java端是用SendRedirect在用戶端重新導向的,所以該方法得到的返回結果如下:
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location: http://localhost/struts2-rest-ex/rest/orders/230.xml
Content-Length: 0
Date: Mon, 27 Oct 2014 03:18:56 GMT
Connection: close
是一堆http頭的原文,只能曲線救國,將其中的Location:後的部分(即重新導向的url),取出來再次get請求,這裡還有一個坑,該url返回時,把port弄丟了,正確的重新導向url應該是:
http://localhost:8080/struts2-rest-ex/rest/orders/230.xml
手動把連接埠拼上,再次get,總算返回正確了
C#以post方式調用struts rest-plugin service的問題