由于实验室项目组正在开发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