Archive for the ‘前端开发’ Category

flash在客户端之间的通信

2009-11-15

假如flash之间要通信,一种形式是通过服务器端的技术,即每个flash会和服务器有一个连接;另一种是客户端的flash之间进行通信,这样不用通过服务器端,会减小服务器的压力.

所以这里就来说说怎么样在flash与flash之间通信,不经过服务器端.

在flash的api中,有一个称为LocalConnection的类,这个类用来干什么的呢?先看Adobe的官方解释:

“使用 LocalConnection 类可以创建一个 LocalConnection 对象,该对象可在一个 SWF 文件中或多个 SWF 文件间,调用另一个 LocalConnection 对象中的方法。 通过本地连接,可以在 SWF 文件之间进行这种通信,而不用使用 fscommand() 或 JavaScript。” (ok, 这边就不解释fscommand这种了).

通过这个类,就可以实现flash之间的通信. 打个比方,假如一个flash在线聊天工具, 当聊天窗口(一个窗口是一个swf)打开了十个的时候, 是不是就要占用服务器的十个连接呢?加入服务器扛得住,那也可以…….

所以我们只要一个连接,当这个连接收到聊天信息的时候,去通知其余九个就可以了.

ok, 现在先来熟悉一个 LocalConnection 这个类. 这个类即有暴露服务给其他flash调用的功能, 也有调用其他flash暴露的服务的功能.

现在,假如想被其他flash通知, 有新聊天信息的时候, 我们应该怎么样搞呢?

先暴露接口吧, 让别人能找到我们.

LocalConnection暴露服务有三种方式, 我们这里只讲其中的两种, 因为第三种不利于代码的移植.

一. 继承LocalConnection,并添加方法。

二. 将 LocalConnection.client 属性设置为实现方法的对象。

三. 创建扩展 LocalConnection 的动态类,并动态附加方法。

先来看第一种方式:

这种方式, 会暴露interfaceName的服务, 而invokeMethod是服务里面的一个方法.

第二种方法呢, 得新建一个类, 被暴露服务的方法, 会在这个类中, 我们这边就取名LocalConnectionClient吧.

这个类就会作为 LocalConnection 的client:

var lc:LocalConnection = new LocalConnection();
lc.client = new LocalConnectionClient();

lc.connect(interfaceName);

通过上面两种方法,就暴露了名为interfaceName的服务…

暴露的服务以后, 收到新消息的flash就可以通过这些服务发通知了.

要去调用上面暴露的服务, 先创建一个 LocalConnection 实例.

var __lc:LocalConnection = new LocalConnection();

__lc.send(interfaceName, “invokeMethod”, “Hello world”);

这里的interfaceName就是上面暴露的服务名, 而invokeMethod是方法, 当然Hello world是参数…..

LocalConnection的使用就是这样简单, 当然还要加上一些对异常事件的捕获.

ok…..今天就到这吧, 上床OpenGL…….

小试red5

2009-06-04

1. 什么是Red5.
Red5是一个开源项目,用于实现flash与服务器端之间通过rtmp(real time messaging protocal)协议通信,可以实现视频、音频的传输,remote shared object等等。相对于FMS, Red5是免费、开源的。
2. 环境搭建(用Tomcat好了).
首先下载Red5,我们这里适用0.7版。下载地址:http://osflash.org/red5/070final,选择相应的版本就可以了。下载安装包比较好,里面资料比较多,有api文档,demo源码等等,推荐下载下来看一下。
搭建Red5的环境非常简单,只要把用到的jar包放到lib目录下面,再配置一下相应的xml文件即可。
在Red5的安装目录下面,有我们要用到的所有东西,目录结构如下:

在Eclipse里面新建一个Dynamic Web Project, 命名为Red5ChatRoom, 直接finish.
把Red5安装目录下的red5.jar和lib目录下的jar包复制一份到Red5ChatRoom项目的WEB-INF/lib下。

接着,修改red5配置文件。
第一个要修改的是web.xml文件,我们可以直接从red5安装目录下面的conf目录下复制一份。
第二个就是把Red5必须要的配置文件放到class path中,这些配置文件是容器一启动的时候,Red5自动去读取的。主要是下面这些配置文件beanRefContext.xml, defaultContext.xml, red5-common.xml, red5-core.xml, 这四个文件是必须的。其中beanRefContext.xml中说明了要加载其他三个文件。
所以,简单的方式就是在WEB-INF目录下面新建一个classes目录,把上面4个文件复制到classes中。
这样,Red5的基本环境就配置完了。

3. 写个简单一点的Demo,实时聊天室.(由于是demo,所以没有检测之类的功能,功能点就是有用户名、能群聊天)
首先实现server端:
package demo;

import java.util.Iterator;
import java.util.Map;

import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.IConnection;
import org.red5.server.api.IScope;
import org.red5.server.api.Red5;
import org.red5.server.api.service.IServiceCapableConnection;

public class Red5RealTimeChatR extends ApplicationAdapter {

 /**
  * 每个新的客户端来连接的时候调用!
  * 这里我们覆盖了父类的实现。
  */
 public boolean appConnect(IConnection con, Object[] params) {
  System.out.println(”new client connectting chat room”);
  return true;
 }
 
 /**
  * 当客户端断开连接的时候调用!
  * 这里我们覆盖了父类的实现。
  */
 public void appDisconnect(IConnection conn) {
  System.out.println(conn.getClient().getId() + ” disconnect”);
 }
 
 
 /**
  * 加入聊天室,必须带上用户名,假如用户名为空,则不能发送消息,也不能收到消息。
  * @param params 客户端调用服务器端的参数。
  */
 public void jionChatRoom(Object[] params) {
  
  String nickName = params[0].toString();
  if (null == nickName || “”.equals(nickName)) {
   return ;
  } else {
   // 设置用户昵称。
   IConnection conn = Red5.getConnectionLocal();
   conn.setAttribute(”nickName”, nickName);
  }

  // 发通知给聊天室的所有人,有新人加入了。
  IScope scope = Red5.getConnectionLocal().getScope();
  Iterator it = scope.getConnections();
  int x = 0;
  for (;it.hasNext();) {
   IConnection tempConn = (IConnection)it.next();
   if (tempConn instanceof IServiceCapableConnection) {
    IServiceCapableConnection sc = (IServiceCapableConnection) tempConn;
    // 服务器端调用客户端flash方法。
    sc.invoke(”showJoinInInfo”, new Object[]{nickName});
   }
  }
  
 }
 
 /**
  * 给聊天室的所有人发送消息
  * @param params
  */
 public void sayToAll(Object[] params) {
  IConnection conn = Red5.getConnectionLocal();
  //conn.setAttribute(”nickName”, nickName);
  String nickName =  conn.getAttribute(”nickName”).toString();
  String sayWhat = params[0].toString();
  // 发消息给聊天室的所有人.
  IScope scope = Red5.getConnectionLocal().getScope();
  Iterator it = scope.getConnections();
  for (;it.hasNext();) {
   IConnection tempConn = (IConnection)it.next();
   if (tempConn instanceof IServiceCapableConnection) {
    IServiceCapableConnection sc = (IServiceCapableConnection) tempConn;
    // 服务器端调用客户端flash方法。
    sc.invoke(”showMessage”, new Object[]{nickName+” : “+sayWhat});
   }
  }
 }
}
这个类继承自ApplicationAdapter, 所以当有rtmp请求时,它可以作为处理类。
写完这个后,得配置到Red5ChatRoom项目里面,用最简单的方法,在class path下面新建一个xml文件,比如Red5ChatRoom-web.xml(Red5默认会加载class path下面的*-web.xml)。
内容如下:
<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE beans PUBLIC “-//SPRING//DTD BEAN//EN” “http://www.springframework.org/dtd/spring-beans.dtd“>
<beans>
 <bean id=”web.context.chatroom” class=”org.red5.server.Context”>
  <property name=”scopeResolver” ref=”red5.scopeResolver” />
  <property name=”clientRegistry” ref=”global.clientRegistry” />
  <property name=”serviceInvoker” ref=”global.serviceInvoker” />
  <property name=”mappingStrategy” ref=”global.mappingStrategy” />
 </bean>
 <bean id=”web.scope” class=”org.red5.server.WebScope” init-method=”register”>
  <property name=”server” ref=”red5.server” />
  <property name=”parent” ref=”global.scope” />
  <property name=”context” ref=”web.context.chatroom” />
  <property name=”handler” ref=”web.handler” />
  <property name=”contextPath” value=”/Red5ChatRoom” />
  <property name=”virtualHosts” value=”*,localhost,localhost:8080,127.0.0.1:8080″ />
 </bean>
 <bean id=”web.handler.chatroom” class=”demo.Red5RealTimeChatR” />
</beans>
这是最简单的Red5项目应用配置。
现在就可以发布到Tomcat下面去了。启动以后,我们得写Flash客户端来联调。

首先,接下来我们就新建一个Flex Project,项目名称就叫ChatRoom吧。
做一个简单的聊天室界面。
图片一张。
代码如下:
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application fontSize=”12″ xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute”>
 <mx:Script>
  <![CDATA[
  
   private var nc:NetConnection;
  
   private function connectAndJoinRoom(e:Event):void
   {
    var nickName:String = nickNameTextInput.text;
    if (nickName == "")
    {
     return;
    } else {
     if (nc == null)
     {
      initialNetConnection();
     }
    }
   }
   
   private function initialNetConnection():void
   {
    nc = new NetConnection();
    nc.addEventListener(NetStatusEvent.NET_STATUS, connectStatus);
    nc.client = this;
    nc.connect("rtmp://127.0.0.1/Red5ChatRoom", null);
   }
   
   private function connectStatus(event:NetStatusEvent) : void
   {
    if (event.info.code == "NetConnection.Connect.Success")
    {
     nc.call("jionChatRoom", null, nickNameTextInput.text);
     sendButton.enabled = true;
    }
   }
   
   private function sendMessage():void
   {
    var sendString:String = inputWhatYouWantSay.text;
    inputWhatYouWantSay.text = "";
    nc.call("sayToAll", null, sendString);
   }
   
   public function showJoinInInfo(message:String) : void
   {
    roomArea.text += message + " 加入聊天室" + "\n";
   }
   
   public function showMessage(message:String) : void
   {
    roomArea.text += message + "\n";
   }
  ]]>
 </mx:Script>
 
 
 <mx:VBox x=”20″ y=”20″>
  <mx:HBox>
   <mx:Label text=”昵称 : “></mx:Label>
   <mx:TextInput id=”nickNameTextInput”>
    
   </mx:TextInput>
   <mx:Button click=”connectAndJoinRoom(event)” label=”加入聊天室”>
    
   </mx:Button>
  </mx:HBox>
  <mx:HBox width=”100%” height=”300″>
   <mx:TextArea height=”100%” width=”100%” id=”roomArea”>
    
   </mx:TextArea>
  </mx:HBox>
  
  <mx:HBox width=”100%”>
   <mx:TextInput width=”100%” id=”inputWhatYouWantSay”>
   
   </mx:TextInput>
   <mx:Button enabled=”false” id=”sendButton” label=”发送” click=”sendMessage()”>
    
   </mx:Button>
  </mx:HBox>
  
 </mx:VBox>
 
</mx:Application>

运行Flex应用,在昵称里面填入内容,加入聊天室以后,就可以和在线的人一起聊天了。

上面是一个非常非常简单的版本,修改一下就可以实现显示在线人员,给特定人员发消息等。

用Java修复不良格式的HTML

2009-06-03

一、前言

以下是在实际工作中提交的一份技术预研报告。
研究起因是外贸版邮件模块一直被外来的格式不良的HTML邮件所困扰,再加上FCK编辑器本身在HTML文本修复上的天生问题,促使我们寻求在服务期后端处理此问题的可能性。

当然最后由于FCK的原因(架构不良,无法扩展),目前暂时还未将此技术应用到线上项目。但我想本次研究也能为后来者指明方向,因此将本次研究结果分享出来。

关键词:标签补偿(tag balance),标签混乱(tag soup 

二、技术预研报告

事实上我们从07年以来一直在围绕FCK研究解决这类tag soup的问题,08年我大致总结了一下FCK的问题也附带研究了一下Java端解决的可能性。(备注:限于篇幅不再罗列)
直到上个月经过讨论,我们决定真正地研究一下Java代码修复方案。

以下就是本次技术预研报告的全文: 

预研人员

冯春

审核人员

 

计划开始日期

09-5-7

计划结束日期

09-5-13

实际开始日期

09-5-7

实际结束日期

09-5-13

附加要求

 

预研目标

提示:说明本次技术预研的主要问题与目标(必须是可以验证的)。

1

使用JAVA开源工具库,将格式不良(bad-format)的HTML修复为格式良好(well-format

要求此工具包拥有:

1)  良好的DOM解析能力

2)  支持标签补偿(Tag-balance)、HTML格式整理

3)  很好的扩展能力,比如:支持自定义过滤器、自定义事件处理器

2

 

3

 

工作成果
提示:说明本次技术预研取得的工作成果(程序、文档、数据等)以及时间。

1

这方面的Java开源工具包,主要是:NekoHTMLHTMLParserHTMLCleaner

其中NekoHTML出现较早,功能较强。所以将主要研究目标选定为它。

需要说明的是HTMLParser我也使用过,主要功能是解析HTML,清理不是它的强项;另外HTMLCleaner没有研究过,但据说小巧好用,值得我们以后研究一下。

 

以下是NekoHTML的背景知识:
1
)作者是IBMxerces团队的主力开发者(在DOM解析领域相当精深),NekoHTML是他基于xerces的一个开源项目。

2xerces解析器是目前Java业界最强大的,其前身是XML4j(以前用过,性能功能都不错)。由IBM捐献给Apache,后来被SUN集成至JDK中(主要是其中的Xalan部分)

2

在研究过程遇到了非常多的问题与障碍。主要问题简单描述一下:

一、在解析HTML文本过程中:

发现nekohtml-1.9.12HTMLScanner在解析非常复杂且不良的网页(新浪首页)时,存在字节数组越界的BUG。我在源码上Fix了该问题,重新打了包,则OK了。 

另外发现某些NekoHTML所申明支持的参数配置,其实是没有作用的。 

另外,经过Neko处理的文档会有以下现象:
1
)标签都变成全大写,且完全符合XHTML(很正常,因为按照XML来解析的)

2)如果文档开头有DOCTYPE则会被自动删除

3)会自动生成一段在<HEAD>之后:

<META http-equiv=”Content-Type” content=”text/html; charset=XXX”>

4)  Neko是不支持自动识别文档编码的,所以解析前需要告诉解析器编码是什么

5)  缺省设置下是不会删除被注释的部分以及脚本的,如要删除则需要自己写Filter 

二、在将(已处理好的)DOM对象转换为HTML文本的过程中:

发现Xalan(2.7.x)TransformerImpl类对一些特殊字符作了过分转义,造成生成后的HTML无法再正常浏览了。

3

 

待解决问题

提示:说明本次技术预研未完成或有待完成的工作及时间。

1

还有一些丢失的内容(比如:DOCTYPE)需要我们自己写代码补齐。

2

需要提交新的第三方类库

3

 

研究结论

提示:论述最终解决问题的思想方法、技术方案等

结论:使用NekoHTML来解决我们的问题完全可行。

但需要:

1)  暂时使用我FIX了BUGnekohtml.jar (待以后向作者报BUG,使其更新)

2)  经过反复组合测试,证明:使用NekoDOMFragmentParser类来解析HTML文本为DOM对象,再用XalanTransformerImpl类输出DOMHTML文本。这对组合配置有最少的BUG,最满足我们的要求。我定义了一个包装类,将两者搭档起来,对最终的输出文本再作一次BUGFIX后,得到的HTML格式完全良好且使用无误。

性能测试:

将新浪首页另存为HTML,大小为418K

处理后的HTML大小为414K,处理时间约为600ms左右。 

单元测试:

共测试两组文件:一组是完整的HTML文档,另一组是HTML片断。

总共143个文件,均处理正常。

 

附上需要引入的第三方类库:

nekohtml-1.9.12-fix.jar

xercesImpl-2.8.1.jar

xalan-2.7.0.jar 

 

         

 

三、总结

Java端主要使用DOM解析器作Tag-balance,这是解决此类问题的正道。

FCK自身也在作Tag-balance,但存在两个严重问题:
1)其算法只能使用正则表达式(由于JS语言本身是不支持DOM解析的),因此不管它如何升级都可能BUG不断。
2)FCK在补偿时添加了过多的额外标签(例如<P>),引起了新的问题发生。

现有的FCK架构非常不良(虽然它问世8,9年,看其架构可知作者在此方面的设计水平),作者目前也正在重构推出新的CFCK。如果新版的FCK能全面支持继承、事件驱动,提供更良好的扩展点,再结合本文,则可以很好地解决在FCK下的大部分HTML文本编辑问题。

谈谈即时通信的开发方案的个人看法

2009-05-25

   随着网站和软件不断发展,各种行业软件或网站越来越需要即时通信软件作为本行业软件的一模块或组成部份,这类即时通信软件的开发并不需求类似于QQ,MSN等专业通信软件的功能,只需求实现与行业软和网站结合以后,文字发送,视频,音频的交流这些主要功能也差不多了。

   如果用传统业C开发即时通信又费时,又费力。对网站来说还要下载,安装,这对用户来说非常不友好。简直是吃力不讨好。现在才用flex+fms的开发,即简单又稳定,只需少量代码即实现即时通信的文字,音视频通信。当然fms的开发版不需要money,但只有10连接而已。要有更多功能,则需要money:$4500。

  那么我即不想花钱,又想要高并发的服务,怎么办呢?有办法,那就flex+red5来实现,red5是用java写的开源流媒体服务,目前评价还是比较高的。至于实现-有待下回分解-唉,最近有点累。

  red5参考网站

  http://osflash.org/red5

  http://www.openred5.com/bbs/index.php

blazed 消息服务器配置总结,优化

2009-05-22

      消息服务(Message Service )提供发布(publish)/订阅(subscribe)机制允许Flex 应用程序发布消息、订阅消息终端(messaging destination),从而实现实时数据的推和协作。

     消息终端通常用作streaming频道或者polling频道二种方式.

     使用streaming频道,服务器端会一直响应HTTP请求直到该频道连接被关闭,它允许服务器向客户端不断传送大量的数据。因为HTTP连接是独一无二的,这实现数据的双向传送,每个streaming AMF或者HTTP频道事实上需要两个浏览器 HTTP连接, 一个连接需要不断处理服务器端与频道紧密相关的客户端的响应。另外需要一个短暂连接,只有当数据需要传送到服务器时,它才脱离浏览器连接池;当短暂连接不再需要时,它立即被释放回浏览器连接池。

    polling频道可以通过简单的时间间隔或者使用服务器等待来配置,如果数据不马上可用 (长轮循)的话。另外,每次轮循响应完成请求。默认下浏览器HTTP 1.1的连接是持续的,浏览器轮循已有的连接,发送并发的轮循请求,以此来减轻轮循的开销。

   当需要准实时通信时,streaming 频道是最好选择

   但是浏览器对每个session都有连接数限制。不同的浏览器,连接最大数以及对session的处理方式都不一样。

IE中每个session的最大连接数为2。 但如果从开始菜单或快捷方式打开多个IE实例,每个IE实例开启不同的进程并拥有各自session。另外,如果我们通过CTRL+N 开启对已有的IE实例一个新的IE窗口,该窗口将与创建它的IE实例共用一个session 。也就是说,如果程序实例开启不同的进程,我们可以通过HTTP streaming建立不限量应用取得服务器端数据;如果通过CTRL+N开启多个窗口,每个session最多建立2个连接。

Firefox中每个session最多建立8个连接。如果从开始菜单或快捷方式打开多个Firefox实例,所有实例开启使用同一进程并共用一个session。既然浏览器对普通的HTTP请求通常只需要一个连接, 理论上我们可以最多可以建立7个HTTP streaming连接。

   所以当Flex同时有其它应用一起使用的话,建议使用长轮询来处理。实战证明长轮询的反应也是很快的。

配置参考如下:

        <channel-definition id=”my-long-polling-amf” class=”mx.messaging.channels.AMFChannel”>
      <endpoint url=”http://{server.name}:{server.port}/{context.root}/messagebroker/amflongpolling” class=”flex.messaging.endpoints.AMFEndpoint”/>
      <properties>
          <polling-enabled>true</polling-enabled>
          <!– 服务器端的潜伏期,也就是服务器会保持与客户端的连接,直到超时或有新消息返回 –>
          <!– 0意味着,服务器不会等待新的消息  –>
    <!– 值-1 也就是说,服务器等待下去,直到有新消息–>
          <wait-interval-millis>-1</wait-interval-millis>
          <!–  polling-interval-millis = 0 表示客户端请求服务器端的间隔期, 0 表示没有任何的延迟 –>
          <polling-interval-millis>100</polling-interval-millis>
          <!–  表示服务器能承受的最大长连接用户数,超过这个限制,新的客户端就会转变为普通的轮询方式 –>
          <max-waiting-poll-requests>50</max-waiting-poll-requests>
      </properties>
  </channel-definition>

 

FLEX 优点,个人几点体会

2009-05-22

flex是一个富客户端的应用方案,在客户端你也可以用javascript+html,或者在IE下的一些控件来实现,但flex有一些独特的优点.

1.在一些场景下javascript代码在运行时,浏览器会提出不安全警告,而flex不会。例子,图片放大缩小功能

2.flex 的开发效率显然要比javascript快一些,能更好的面向对象开发,而html不能继承,而且跨浏览器。

3. flex 多媒体开发有更好的支持,音视频处理很方便

4.编译后运行,性能表现要与javascript好

缺点:

1 flex需要编译成swf下载才能运行,文件相对比较大,如果网络流量有一定要求

2 新学习一门语言,具体学习成本

Flex的二个重要功能,ComboBox组件的索引定位,XMLList动态组装

2009-05-20

1.XMLList动态组装例子

   var types:Array = [["Murphy","Pat"],["Thibaut","Jean"], ["Smith","Vijay"]] ;

   var postTypeData :XMLList = new XMLList();
   for (var i:int = 0; i < types.length; i++) {
           var newnode:XML = new XML(); 
           newnode = <node label={types[i][0]} data={types[i][1]}/>;
           postTypeData = postTypeData+newnode;   
   } 
   comboBox.dataProvider=postTypeData; 

2 ComboBox组件的索引定位

  <mx:ComboBox id=”comboBox”  labelField=”@label” width=”157″ paddingTop=”7″ dataProvider=”{postTypeData}”>

  public function loadRow():void
  {
     comboBox.selectedItem = postTypeData.(@data==post.type); 
  }

用@RemotingDestination标签代替flex远程对象配置

2009-05-18

之前我们暴露BlazeDS remoting需要如下配置

<!– Expose the productService bean for BlazeDS remoting –>
<bean id=”product” class=”org.springframework.flex.messaging.remoting.FlexRemotingServiceExporter”>
<property name=”messageBroker” ref=”mySpringManagedMessageBroker”/>
<property name=”service” ref=”productService”/>
</bean>

或者

<flex:remoting-destination ref=“productService” />

现在我们只需 @RemotingDestination  annotation 标签 来代替

例子

package org.springframework.flex.integration.service;

import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.flex.remoting.RemotingExclude;
import org.springframework.flex.remoting.RemotingInclude;
import org.springframework.stereotype.Component;

@Component
@RemotingDestination
public class FooService {

    @RemotingInclude
    public String bar() {
        return “bar”;
    }

    @RemotingExclude
    public String baz() {
        return “baz”;
    }
}

注,org.springframework.flex.remoting.RemotingDestination的jar包需单独下载

org.springframework.flex-1.0.0.RC1.jar下载

应用程序初始化失败(0xC0000034)错误的定位方法

2009-04-10
  通常在遭遇应用程序启动过程中应用程序初始化失败或应用程序配置错误的时候,我们大致能够断定该错误产生的原因在于某个dll模块加载失败或是与manifest指定版本不匹配造成的。在今天的一例 0xC0000034 错误处理过程中摸索出两个比较可行的方法来处理。
 
问题重现:
 
  在问题锁定之后,我们能够重新布置故障现场使问题重现,通过 调试环境我们能够看到相关模块的加载过程,而在遭遇的一例case中,是由于其中ATL80.dll缺失出现了类似问题:
“aliim.exe”: 已加载“H:\Assist\IMClient-RV\bin\Debug\AliIM.exe”,已加载符号。
“aliim.exe”: 已加载“C:\WINDOWS\system32\ntdll.dll”,未加载任何符号。
“aliim.exe”: 已加载“C:\WINDOWS\system32\kernel32.dll”,未加载任何符号。
“aliim.exe”: 已加载“C:\WINDOWS\system32\comctl32.dll”,未加载任何符号。
“aliim.exe”: 已加载“C:\WINDOWS\system32\advapi32.dll”,未加载任何符号。
“aliim.exe”: 已加载“C:\WINDOWS\system32\rpcrt4.dll”,未加载任何符号。
…………
“aliim.exe”: 已加载“C:\WINDOWS\system32\oleaut32.dll”,未加载任何符号。
“aliim.exe”: 已加载“C:\WINDOWS\WinSxS\x86_Microsoft.VC80.ATL_1fc8b3b9a1e18e3b_8.0.50727.762_x-ww_cbb27474\ATL80.dll”,已加载符号。
  此时,我们可以简单的将 C:\WINDOWS\WinSxS\x86_Microsoft.VC80.ATL_1fc8b3b9a1e18e3b_8.0.50727.762_x-ww_cbb27474\ATL80.dll 文件重新命名,令其无法被加载,启动 AliIM.exe 的时候就会出现下图:
 
 
方法一:有对比有真相
 
  上面的重现方法实际上就是根据观察调试过程中模块加载顺序后定位到的模块缺失来使过程重现的,这就是我们的第一个方法:对此调试过程中的模块加载输出:
  在一个正常的加载过程中,模块加载信息会顺利的往下持续打印出来,而在异常环境中会看到如下的输出内容:
…………
“aliim.exe”: 已加载“C:\WINDOWS\system32\oleaut32.dll”,未加载任何符号。
调试器:: 在进程加载过程中引发了未处理的无法继续的异常
程序“[4024] aliim.exe: 本机”已退出,返回值为 -1073741772 (0xc0000034)。

  这里原本应该输出 ATL80.dll 加载成功的消息不再出现了,但是通过对比两次加载输出就能够知道加载失败的是 ATL80.dll,但是需要注意的是,WinSxS 下的 ATL80 版本不只一个,具体缺失的是哪一个可以通过打开 WinSxS 下的目录进行确定。
  这是一种方法,但是在本机却不是那么有效的一种方法,因此在本机出现错误的时候我们甚至都没有机会能够比较正常过程中是怎样的情况。所以,这种方法实际上生效的场景是用于辅助解决远程机器上用户应用程序加载失败的模块定位。
 
方法二:有图有真相
 
  实际上,这是一种更为有效和快捷,同时也更具普遍应用价值的方法,借助于 ProcMon 应用程序工具,可以比较容易地定位到问题所在。
  ProcMon 可以用于监控应用程序的重要 API 活动过程并能清晰的列举出重要参数,只需简单的配置就能够锁定问题所在。

ProcMon 配置

 Result 列的 NAME NOT FOUND 指出了通过 CreateFile API打开失败的模块文件
Path 列指出了打开失败的文件名称
 

一些关于特殊字符的问题

2009-04-03

在外贸凤凰项目中,经常会碰到QA提特殊字符的bug,整个项目下来,同类的bug估计也又几十个。

这里稍微总结一下,一般分三种情况。

1.html代码中的特殊字符问题
 
表现形式:页面破页,错乱之类

 
原因:在页面中有html字符或者JavaScript起了效果
 
这种错误一般情况是在jsp或者vm页面中有动态代码传入的值引起的,如下代码:
  <div>$count</div>
      
程序员一般在自己做的时候认为count是数字,而自测的时候也一般会用数字去测试,那当然没有问题,但是不巧是我们敬业的QA同学在测试时候总是想法设法传一些奇怪的东西进去。如上,如果count传值过来是一些html那就惨了比如<div><div>test</div></div>,那完全不是自己想要结果,如果传入<script>alert(’xxx’)</script>,那结果更加尴尬了!所以我们需要在vm或者jsp中提供方法将”<““>”两个特殊符号转义成“&lt;”“&gt;”。这样可能就能得到我们想要的结果了吗?等等,我们敬业的QA同学还有奇招,还一种情况那就是不间断的空格,我们知道如果只在html敲空格的话,其实只有一个空格的间距,所以我们还需要把空格转义成为“&nbsp;”。其实还有两个特殊字符就是“””“&”,我们最好在显示时也把他们转义“&quot;”“&amp;”。在我们项目中其实都提供了专门的工具方法来转义,只是大家在做的时候都不太留意这些,希望大家能养成好习惯,在页面上显示的时候都要做好转义工作。

2.JavaScript中的特殊字符问题
 
表现形式:JavaScript直接报错
 
原因:语法错误
 
JavaScript中引号的没有转义造成语法错误,这种情况比较多见的时候我们做Ajax请求回数据时候在客户端处理的时候出错了。如下代码:
  var str = ‘test’;
 
这段代码当然不会又什么问题,但是如果str的值是后台返回处理是如果又个引号
  var str =”test’;
 
很明显语法就报错了,应该改成var str = ‘\’test’;
 
3.html
中的JavaScript的特殊字符问题

     
蛮多情况我们会遇到这种情况,我们通过Ajax从服务端取来数据在客户端处理,不光要显示,还需要修改后再保存回数据库,如果像第一种情况那样转义之后保存就不对了。那怎么办呢?其实很简单,我们通过JavaScript将后台数据转义,再上传会服务器前在转义回来就可以,在我们XUI框架里面,已经都提供了工具方法,只要调用xui.util.StringUtil中的htmlEncodehtmlDecode方法就可以。这里稍微打下广告,如果我们整体都是用xui提供的组件来做的话,那你就不用为这些烦恼了,因为组件已经把这些都做掉了。

      最后说一下,我经常发现有人在html中直接写绑定事件,而且我发现很多人还蛮喜欢这样,其实这样不太好,我们在XUI框架里面都已经提供事件绑定的方法,直接这样写的话相对容易出现问题。如果一定要这样写的话,建议下,就是在JavaScript中我们定义变量时候,尽量都用单引号,而在写html时候都用双引号。如下:
 <input type=”button” onclick=”test(’123′)” />,
虽然htmlJavaScript不像java那么严格,里面单双引号怎么写都不会报错,但是混乱的写法总是bug的温床,遵守规范可以避免更多bug出现的几率。