由於實驗室項目組正在開發ERP系統,客戶端有PC CS、BS、Android等多種展現方式。前期為了快速開發出產品雛形,PC端使用.NET開發,Android使用JavaEE做為服務后台。本人參與了.NET后台開發以及JavaEE后台開發。擔任技術攻關角色。
隨着系統的完善逐漸成熟,早期的系統架構已經不能滿足現在的需求,問題在於:由於平台的限制,不同平台的客戶端需要不同平台的后台提供服務,也就是說相同的業務需要開發多套后台服務出來。這種架構必定存在問題。
而要做到平台的無關性,就要制定標准的通訊協議和數據契約。由於.NET平台比較成熟,經過考慮,本人決定使用WCF作為APPServer,沒有使用JavaEE。使用HTTP+JSON作為通信協議與數據契約,提供統一的服務接口,為不同的客戶端平台提供后台服務。
在使用此解決方案前,需要做一些WCF的技術攻關以及性能調優,以避免后期系統完全使用此方案造成大規模的故障。在研究WCF REST編程模型時,遇到了以下問題及解決方案:
問題描述一、
在使用POST方式向服務提交數據時,出現HTTP400異常,以下代碼描述:
服務接口定義:
[OperationContract]
[WebInvoke(ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, Method = "POST", BodyStyle = WebMessageBodyStyle.Bare)]
Stream HelloData(MyData data);
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare)]
Stream HelloDataStr(String data);
實現只是簡單的把傳入的數據打印出來,略
客戶端調用:
方法一、
private static void HelloDataClient()
{
WebClient client = new WebClient();
client.Headers["Content-Type"] = "application/json";
string data = "{\"ID\":1,\"Name\":\"ss\"}";
string str = client.UploadString("http://localhost:1122/HelloData", "POST", data);
Console.WriteLine(str);
}
方法二
private static void HelloDataStrClient()
{
WebClient client = new WebClient();
string str = client.UploadString("http://localhost:1122/HelloDataStr", "POST", "ss");
Console.WriteLine(str);
}
以上兩個方法對用調用兩個不同的服務,問題在於使用Mydata數據契約的方法一OK,方法二出現HTTP400錯誤。為什么自定義類型的可以,而基本數據類型的不可以?起初認為自定義數據類型自己已經做了序列化,而string不是自己做的可能跟序列化有關。那沒有用UriTemplate是不是參數映射出了問題?因為方法一已經成功,說明WCF會將HTTP請求參數默認映射到僅有的一個服務接口的參數上。排除此猜測。
方法后來做了以下迭代測試:
將方法二改為:
private static void HelloDataStrClient()
{
WebClient client = new WebClient();
string str = client.UploadString("http://localhost:1122/HelloDataStr", "POST", String.Empty);
Console.WriteLine(str);
}
發現調用成功,說明數據有問題。數據有問題就是數據的格式有問題,但是服務契約二沒有聲明Request的格式為JSON。那么他默認為什么呢?把方法二再改如下:
private static void HelloDataStrClient()
{
WebClient client = new WebClient();
client.Headers["Content-Type"] = "application/json";
string str = client.UploadString("http://localhost:1122/HelloDataStr", "POST", "\"ss\"");
Console.WriteLine(str);
}
調用成功。
注意:JSON格式默認為“”引起,所以 "\"ss\""不能寫為“ss”,否則還是HTTP400錯誤。因為未識別數據,將數據拼接到其他字節了吧。
問題描述二、
沒有使用UriTemplate做參數的映射,那多個參數是怎么映射的?將方法二改為:
服務契約二:
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped)]
Stream HelloDataStr(String data1,string data2);
客戶端:
private static void HelloDataStrClient()
{
WebClient client = new WebClient();
client.Headers["Content-Type"] = "application/json";
string str = client.UploadString("http://localhost:1122/HelloDataStr", "POST", "{\"data1\":\"hh\",\"data2\":\"ss\"}");
Console.WriteLine(str);
}
調用成功,並且成功打印了兩個參數。注意服務契約的接口定義屬性WebMessageBodyStyle.Wrapped,此屬性將兩個參數進行了包裝,否則無法映射。
附:JAVA調用代碼:
public static void main(String[] args) {
// TODO Auto-generated method stub
HelloClient();
HelloDataClient();
HelloDataStrClient();
}
private static void HelloClient(){
URLClient client = new URLClient();
String resultStr = client.getDocumentAt("http://localhost:1122/Hello");
MyData data = assembleModel(resultStr);
System.out.print("Hello Response content: " +resultStr);
System.out.println("MyData Name: " +data.getName());
}
private static void HelloDataClient(){
try {
String postUrl = "http://localhost:1122/HelloData";
String postData = "{\"data1\":1,\"data2\":\"ss\"}";
HttpClient hClient = new DefaultHttpClient();
HttpPost post = new HttpPost(postUrl);
StringEntity s = new StringEntity(postData);
s.setContentEncoding("UTF-8");
s.setContentType("application/json");
post.setEntity(s);
HttpResponse response = hClient.execute(post);
HttpEntity responseEntity = response.getEntity();
String resultStr = inputStream2String(responseEntity.getContent());
MyData data = assembleModel(resultStr);
System.out.println("HelloDataStr Response content: "
+ resultStr);
System.out.println("MyData Name: " +data.getName());
} catch (Exception e) {
// TODO: handle exception
}
}
private static void HelloDataStrClient(){
try {
String postUrl = "http://localhost:1122/HelloDataStr";
String postData = "{\"data1\":1,\"data2\":\"ss\"}";
HttpClient hClient = new DefaultHttpClient();
HttpPost post = new HttpPost(postUrl);
StringEntity s = new StringEntity(postData);
s.setContentEncoding("UTF-8");
s.setContentType("application/json");
post.setEntity(s);
HttpResponse response = hClient.execute(post);
HttpEntity responseEntity = response.getEntity();
String resultStr = inputStream2String(responseEntity.getContent());
System.out.println("HelloDataStr Response content: "
+ resultStr);
} catch (Exception e) {
// TODO: handle exception
}
}
public static String inputStream2String(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = -1;
while ((i = is.read()) != -1) {
baos.write(i);
}
return baos.toString();
}
private static MyData assembleModel(String jsonStr) {
MyData model = null;
try {
JsonConvertor jsonConvertor = new JsonConvertor();
MyData[] stus = (MyData[]) jsonConvertor
.convertToObj(jsonStr,MyData.class);
model = stus[0];
} catch (Exception e) {
e.printStackTrace();
}
return model;
}
原創:轉載請標明出處:http://www.cnblogs.com/sh91/p/3273072.html