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 }
代码不复杂,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 try 27 { 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 finally 45 { 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 }
这二种常用的调用方式,居然全跪了,返回的结果是一堆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 finally 31 { 32 if (readStream != null) 33 { 34 readStream.Close(); 35 } 36 if (clientSocket != null) 37 { 38 clientSocket.Close(); 39 } 40 } 41 return result; 42 }
总算调用成功了,但是由于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,总算返回正确了