Flex通信篇——构建企业级HTTP通信层
来源:互联网 发布:阿里巴巴国际交易软件 编辑:程序博客网 时间:2024/06/06 05:40
概述
RIA和SOA是一对绝配。SOA强调把业务以接口方式向外界提供不关注前端的呈现,而RIA则强调用户体现,结合两者优势能够设计出用户体现良好、灵活的、易扩展、易集成的系统。要处理好RIA前端和SOA后端,需要搭建一个健壮的企业级通信层,该层职责:
- 负责处理RIA前端和SOA后端的数据交互。
- 封装SOA业务接口,便于开发调用。
- 采用异步通信方式,SOA业务接口请求返回时进行回调。
- SOA业务接口调用错误处理机制。
SOA业务接口的设计
- 不使用webservice,采用自定义数据格式,数据简单些。
- 针对Flex,返回格式采用xml数据格式方便写。
- 安全策略:用户调用登录接口后返回登录信息,其中还回信息中包含令牌(session),每次调用登录以外的业务接口都必须传入令牌参数作验证。同一用户,每次登录令牌值都会刷新,即:最后登录的获得使用权。
- 大部分业务接口采用GET方式调用,少数采用POST方式,后台应该统一处理GET,POST参数。
SOA通信格式的设计
业务接口调用成功返回格式(XML)
<?xml version="1.0" encoding="utf-8">
<rsp>
{业务所需的XML节点信息}
</rsp>
业务接口调用失败返回格式(XML)
<?xml version="1.0" encoding="utf-8">
<error_rsp>
<code>{错误码}</code>
<msg>{错误描述}</msg>
</error_rsp>
业务接口常用参数
- v:version,业务接口版本号,用于版本控制,同一接口根据不同版本号可以有不同的实现逻辑。
- f:format,返回格式,指定返回信息的格式,常用的有xml,json,Flex使用xml方便些。
- api:业务接口名称,用于区分接口类型。
- t:时间戳,用于解决客户端浏览器缓存问题,服务端不处理该参数。
- session:令牌/会话码,除了登录接口,其他接口一般都需要这个参数。
调用例子
- 登录成功
- Request: http://server1:2009/LCMS2/api.jhtm?api=lcms.user.login&v=2.0&f=xml&uname=Hunk&pwd=123
- Reponse:
<?xml version="1.0" encoding="UTF-8" ?>
<rsp>
<uid>51</uid>
<urole>4</urole>
<session>cbff8aca-8b56-48d7-a740-534f3a84e575</session>
</rsp>
- 登录失败
- Request: http://server1:2009/LCMS2/api.jhtm?api=lcms.user.login&v=2.0&f=xml&uname=User1&pwd=123
- Reponse:
<?xml version="1.0" encoding="UTF-8" ?>
<error_rsp>
<code>500</code>
<msg>用户不存在</msg>
</error_rsp>
- 获取用户列表
- Request: http://server1:2009/LCMS2/api.jhtm?api=lcms.user.get&v=2.0&f=xml&session=cbff8aca-8b56-48d7-a740-534f3a84e575&page_no=1&page_size=10
- Reponse:totalResults是不分页时的查找总数量,返回第一页的item(用户),每页10行
<?xml version="1.0" encoding="UTF-8" ?>
<rsp>
<totalResults>37</totalResults>
<item><uid>51</uid><uname>hunk</uname><urole>4</urole></item>
<item><uid>48</uid><uname>hunk4</uname><urole>3</urole></item>
</rsp>
- 删除用户
- Request: http://server1:2009/LCMS2/api.jhtm?api=lcms.user.delete&v=2.0&f=xml&session=cbff8aca-8b56-48d7-a740-534f3a84e575&del_uid=36
- Reponse:
<?xml version="1.0" encoding="UTF-8" ?>
<rsp>
<true/>
</rsp>
HttpRequest类
该类用于封装请求参数,方便调用,声明为internal,只在包内使用,代码如下:
package cwn.lcms
{
import mx.collections.ArrayCollection;
internalclass HttpRequest
{
//用于存放Get参数
privatevar _GetParams:ArrayCollection = new ArrayCollection();
//用于存放Post参数
privatevar _PostParams:ArrayCollection = new ArrayCollection();
//根路径
publicvar RootUrl:String;
privatevar _Disposed:Boolean = false;
publicfunction HttpRequest(root:String = "")
{
RootUrl = root;
}
//需要对参数进行url加密
privatefunction Encode(value:String):String
{
return encodeURIComponent(value);
}
publicfunction AddGetParam(name:String, value:String):void
{
_GetParams.addItem(name + "=" + Encode(value));
}
publicfunction AddPostParam(name:String, value:String):void
{
_PostParams.addItem(name + "=" + Encode(value));
}
publicfunction GetUrl():String
{
var url:String = RootUrl;
if (url.lastIndexOf("?") < 0)
url += "?";
for (var i:int = 0; i < _GetParams.length; i++)
{
url += _GetParams[i] + "&";
}
if (_GetParams.length > 0)
url = url.substr(0, url.length - 1);
return url;
}
publicfunctionget HasPostData():Boolean
{
return _PostParams.length > 0;
}
publicfunction GetPostData():String
{
if (!HasPostData)
returnnull;
var data:String = "";
for (var i:int = 0; i < _PostParams.length; i++)
{
data += _PostParams[i] + "&";
}
data = data.substr(0, data.length - 1);
return data;
}
publicfunction Dispose():void
{
if (_Disposed)
return;
_Disposed = true;
_GetParams.removeAll();
_PostParams.removeAll();
_GetParams = null;
_PostParams = null;
}
}
}
各种数据类
定义各种业务接口相关的数据类,把XML节点转成Object,利用IDE智能感知,方便编码,以下是UserData类的定义。
package cwn.lcms.data
{
publicclass UserData
{
publicvar Id:String = "";
publicvar Name:String = "";
publicvar Password:String = "";
publicvar Session:String = "";
publicvar Role:int = 0;
publicfunction UserData(xml:XML = null)
{
FromXml(xml);
}
publicfunction FromXml(xml:XML):void
{
if (xml == null)
return;
Id = xml.uid;
Name = xml.uname;
Role = xml.urole;
Session = xml.session;
}
publicfunction Clone():UserData
{
var data:UserData = new UserData();
data.Id = Id;
data.Name = Name;
data.Password = Password;
data.Session = Session;
data.Role = Role;
return data;
}
}
}
WebAPI类
该类是通信层最核心的类,以静态属性、方法为主,先定义一些主要的属性和工具方法,如下:
package cwn.lcms
{
import cwn.lcms.data.UserData;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.external.ExternalInterface;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLVariables;
import mx.collections.ArrayCollection;
publicfinalclass WebAPI
{
privatestaticvar _Debug:Boolean = false; //调试控制
privatestaticvar _HttpCache:ArrayCollection = new ArrayCollection(); //存放http请求
publicstaticvar Url:String = null; //根路径
publicstaticvar Session:String = null; //会话码
publicstaticvar SessionErrorFunction:Function; //会话错误回调方法
publicstaticvar CurrentUser:UserData = null; //当前登录用户数据
privatestaticfunction RemoveCache(value:Object):void
{
var i:int = _HttpCache.getItemIndex(value);
if (i >= 0)
{
var loader:URLLoader = _HttpCache.removeItemAt(i) as URLLoader;
if (loader != null)
{
loader.removeEventListener(IOErrorEvent.IO_ERROR, IOErrorEventHandler);
loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, SecurityErrorHandler);
}
}
}
//执行HTTP请求并缓存请求,callbackXml:Function(result:XML):void
privatestaticfunction Invoke(http:HttpRequest, callbackXml:Function = null):void
{
if (_Debug)
{
trace(http.GetUrl());
}
var loader:URLLoader = new URLLoader();
_HttpCache.addItem(loader);
loader.addEventListener(IOErrorEvent.IO_ERROR, IOErrorEventHandler);
loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, SecurityErrorHandler);
loader.addEventListener(Event.COMPLETE, function(event:Event):void
{
OnInvokeCallback(loader.data, callbackXml);
RemoveCache(loader);
});
var request:URLRequest = new URLRequest(http.GetUrl());
request.method = "GET";
if (http.HasPostData) //当有Post参数时,改用POST方式请求
{
request.method = "POST";
request.data = new URLVariables(http.GetPostData());
}
loader.load(request);
}
//HTTP请求成功回调,callbackXml:Function(result:XML):void
privatestaticfunction OnInvokeCallback(response:Object, callbackXml:Function = null):void
{
try
{
if (_Debug)
{
trace("rsp:" + response);
}
var result:XML = XML(response);
if (result.localName() == "rsp") //调用业务接口成功
{
if (callbackXml != null)
callbackXml(result);
}
elseif (result.localName() == "error_rsp") //调用业务接口错误
{
if (int(result.code) == 8 && SessionErrorFunction != null) //session错误处理
{
SessionErrorFunction();
LcmsError.ShowInfo("该用户已在其他机器上登录,请重新登录。");
}
else
LcmsError.ShowError(result); //输出错误信息
if (callbackXml != null)
callbackXml(null);
}
else
LcmsError.ShowInfo("[数据格式错误]/r/n" + response); //输出错误信息
}
catch (e:Error)
{
LcmsError.ShowInfo("[未知异常]/r/n" + e.message + "/r/n" + e.getStackTrace()); //输出错误信息
}
}
//HTTP请求错误处理
privatestaticfunction SecurityErrorHandler(event:SecurityErrorEvent):void
{
LcmsError.ShowInfo("[无访问权限]/r/n" + event.text); //输出错误信息
RemoveCache(event.currentTarget);
}
//HTTP请求错误处理
privatestaticfunction IOErrorEventHandler(event:IOErrorEvent):void
{
LcmsError.ShowInfo("[服务器连接失败]/r/n" + event.text); //输出错误信息
RemoveCache(event.currentTarget);
}
//创建HTTP请求,并设置必须的参数
privatestaticfunction CreateRequest(api:String, version:String = "2.0", format:String = "xml"):HttpRequest
{
var http:HttpRequest = new HttpRequest();
http.RootUrl = Url;
http.AddGetParam("api", api);
http.AddGetParam("v", version);
http.AddGetParam("f", format);
var date:Date = new Date();
http.AddGetParam("t", date.time.toString());
return http;
}
}
}
然后,就可以根据业务需要封装所需的接口,下面简单介绍几个接口。
- 登录
publicstaticfunction Login(name:String, password:String, callbackXml:Function = null):void
{
var http:HttpRequest = CreateRequest("lcms.user.login");
http.AddGetParam("uname", name);
http.AddGetParam("pwd", password);
Invoke(http, callbackXml);
http.Dispose();
}
- 获取用户列表
publicstaticfunction GetUser(name:String = null, role:String = null, pageNO:String = "1", pageSize:String = "25", callbackXml:Function = null):void
{
var http:HttpRequest = CreateRequest("lcms.user.get");
http.AddGetParam("session", Session);
if (name != null)
http.AddGetParam("uname", name);
if (role != null)
http.AddGetParam("urole", role);
if (pageNO != null)
http.AddGetParam("page_no", pageNO);
if (pageSize != null)
http.AddGetParam("page_size", pageSize);
Invoke(http, callbackXml);
http.Dispose();
}
- 删除用户
publicstaticfunction DeleteUser(id:String, callbackXml:Function = null):void
{
var http:HttpRequest = CreateRequest("lcms.user.delete");
http.AddGetParam("session", Session);
http.AddGetParam("del_uid", id);
Invoke(http, callbackXml);
http.Dispose();
}
使用WebAPI
- WebAPI初始化设置
privatefunction SessionError():void
{
//跳转到登陆…
}
…
cwn.lcms.WebAPI.Url = "http://server1:2009/LCMS2/api.jhtm";
cwn.lcms.WebAPI.SessionErrorFunction = SessionError;
cwn.lcms.WebAPI.Session = null;
cwn.lcms.WebAPI.CurrentUser = null;
- 登录
privatefunction LoginCallback(xml:Object):void
{
//…
cwn.lcms.WebAPI.Session = null;
cwn.lcms.WebAPI.CurrentUser = null;
if (xml == null)
return;
var user:UserData = new UserData(XML(xml));
//…
cwn.lcms.WebAPI.CurrentUser = user;
if (user.Session != "")
cwn.lcms.WebAPI.Session = user.Session;
//登陆成功跳转…
}
…
cwn.lcms.WebAPI.Login("Hunk", "123", LoginCallback);
- 获取用户列表
function GetUserCallback(xml:Object):void
{
if (xml == null)
return;
_Data.removeAll();//ArrayCollection
foreach (var item:XML in xml.item)
{
var user:UserData = new UserData(item);
_Data.addItem(user);
}
//数据绑定
}
…
cwn.lcms.WebAPI.GetUser(null, null, "1", "25", GetUserCallback);
注:设计不唯一,上述是已实践的个案参考。
系列索引
Flex通信篇——Flex和外部应用程序进行通信
Flex通信篇——Flex和外部进行异步通信
Flex通信篇——Flex键盘组合键
Flex通信篇——构建企业级HTTP通信层
后记
写Blog有一段时间,终于能完成一个完整系列,即使略带稚气,也要好好表彰下自己:-)。
- Flex通信篇——构建企业级HTTP通信层
- Flex通信篇——Flex键盘组合键
- Flex通信篇——Flex和外部应用程序进行通信
- Flex通信篇——Flex和外部进行异步通信
- Flex基本通信方式(http,webservice,remoteObject)
- flex通信
- HTTP协议——通信机制
- Android网络——Http通信
- Android学习笔记——Http通信
- HTTP网络通信框架——Volley
- Http 通信
- http通信
- HTTP 通信
- Http通信
- Http通信
- Http通信
- HTTP 通信
- Http通信
- java url 传递特殊字符转译问题
- 编译时报错 error spawning c1.exe
- typedef关键字的理解
- ubuntu9.10中文语言包升级源
- 关于URL中的特殊字符
- Flex通信篇——构建企业级HTTP通信层
- 你好Android-----Android新手入门
- MongoDB数据库操作和程序基础文档
- ICE和ACE高效网络编程中间平台--远程调用中间件
- Response.Redirect在新窗口打开
- Spring 简单介绍
- 74LS595
- python 利用win32com操作excel
- wo de tupian