zoukankan      html  css  js  c++  java
  • Flex HTTPService使用与.NET服务端监听(node.js 友情客串)

    一、Flex端HTTPService代码

    功能说明

      Flex中,很多类都可以通过两种方式进行使用和配置,一种是MXML标签方式,另一种ActionScript编程方式,这两种方式稍后都将进行介绍。

      本例只对HTTPService的使用进行简单介绍,程序主要完成从服务器端请求xml数据并加载绑定到Flex端的DataGrid上。

      以下是xml文档(category.xml)内容:

    <?xml version="1.0" encoding="UTF-8"?>
    <catalog>
    	<category>
    		<name>Dairy</name>
    		<categoryID>4</categoryID>
    	</category>
    	<category>
    		<name>Deli</name>
    		<categoryID>5</categoryID>
    	</category>
    	<category>
    		<name>Fruit</name>
    		<categoryID>3</categoryID>
    	</category>
    	<category>
    		<name>Meat</name>
    		<categoryID>1</categoryID>
    	</category>
    	<category>
    		<name>Seafood</name>
    		<categoryID>6</categoryID>
    	</category>
    	<category>
    		<name>Vegetables</name>
    		<categoryID>2</categoryID>
    	</category>
    </catalog>
    

    主要属性

    名称类型说明
     url Property  HTTP请求的地址 
     fault Event  当请求失败时触发 
     result Event  当请求成功是触发 
     send Method  发送请求 
     headers Property  用于自定义HTTP请求头 
     lastResult Property  最后一次请求成功时返回的数据 
     method Property  HTTP请求方式(get、post、delete、put) 
    requestTimeout  Property  请求超时时间 
    resultFormat Property

    对服务器响应的数据的解析方式,默认为object,可以设置为object、array、xml、flashvars、text、e4x,详见官方API

     contentType Property 

    请求发送的数据内容类型,默认为application/x-www-form-urlencoded,可设置为application/xml 

      关于Flex的API完全文档可以查阅官方文档http://flex.apache.org/asdoc/index.html

    Flex客户端代码

      ①MXML方式

       既然是使用MXML方式,肯定会使用标签,这里使用的标签是<mx:HTTPService/>因为是标签,所以除了上面介绍的属性,还必需一个id属性来使AS方便调用:

    <mx:HTTPService id="httpService" url="http://localhost:5025" fault="onHttpServiceFault(event)" result="onHttpServiceSuccess(event)"/>

      上面代码设置了当请求失败的fault事件和当请求成功的result事件,下面是在请求失败时做的简单处理和在请求成功时,将响应的XML数据绑定到DataGrid上。

    protected function onHttpServiceFault(event:FaultEvent):void
    {
    	Alert.show(event.message.toString());
    }
    
    protected function onHttpServiceSuccess(event:ResultEvent):void
    {
    	try {
    		var dataSource:ArrayCollection = event.result.catalog.category as ArrayCollection;
    		dgData.dataProvider = dataSource;
    	} catch(e:Error) {
    		Alert.show(event.result.toString());
    		dgData.dataProvider = null;
    	}
    }
    
    // 下面是对应的DataGrid的MXML代码
    <mx:DataGrid id="dgData" width="300">
    	<mx:columns>
    		<mx:DataGridColumn headerText="类型ID" dataField="categoryID"/>
    		<mx:DataGridColumn headerText="类别名称" dataField="name"/>
    	</mx:columns>
    </mx:DataGrid>

      这里采用的是在接收到数据是,使用AS代码将数据源绑定到DataGrid上,同样可以使用MXML的方式进行绑定,只需将dataProvider属性移到<mx:DataGrid/>标签中即可:

    <mx:DataGrid id="dgData" width="300" dataProvider="{httpService.lastResult.catalog.category}">

      最后就是需要用一个按钮,在点击按钮的时候发送请求,为了演示携带参数的请求,我在Flex客户端添加了一个TextInupt用于填入请求的xml文件名,为了避免恶意输入带路径的字符串,在Flex端做了简单的验证。以下是点击按钮的AS代码和文本框及按钮的MXML代码:

    protected function loadData(event:MouseEvent):void
    {
    	var fileName:String = txtDataFile.text;
    	// 只允许加载URL同目录的文件,避免恶意加载
    	var namePassed:Boolean = fileName.indexOf('/') === -1 && fileName.indexOf('\') === -1;
    	if (namePassed) {
    		httpService.send({ filename : fileName });
    	} else {
    		Alert.show("禁止输入包含目录的路径");
    	}
    }
    
    // MXML代码
    <mx:TextInput id="txtDataFile" text="category.xml" x="22" y="10" width="150" height="25"/>
    <mx:Button id="btnLoadData" label="加载数据" x="192" y="10" width="130" height="25" click="loadData(event)"/>

      下面是Flex端MXML方式完整代码:

    <?xml version="1.0" encoding="utf-8"?>
    <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    			   xmlns:s="library://ns.adobe.com/flex/spark" 
    			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:layout="org.osmf.layout.*">
    	<fx:Script>
    		<![CDATA[
    			import mx.collections.ArrayCollection;
    			import mx.controls.Alert;
    			import mx.rpc.events.FaultEvent;
    			import mx.rpc.events.ResultEvent;
    			
    			protected function onHttpServiceFault(event:FaultEvent):void
    			{
    				Alert.show(event.message.toString());
    			}
    			
    			protected function onHttpServiceSuccess(event:ResultEvent):void
    			{
    				try {
    					var dataSource:ArrayCollection = event.result.catalog.category as ArrayCollection;
    					dgData.dataProvider = dataSource;
    				} catch(e:Error) {
    					Alert.show(event.result.toString());
    					dgData.dataProvider = null;
    				}
    			}
    			
    			protected function loadData(event:MouseEvent):void
    			{
    				var fileName:String = txtDataFile.text;
    				// 只允许加载URL同目录的文件,避免恶意加载
    				var namePassed:Boolean = fileName.indexOf('/') === -1 && fileName.indexOf('\') === -1;
    				if (namePassed) {
    					httpService.send({ filename : fileName });
    				} else {
    					Alert.show("禁止输入包含目录的路径");
    				}
    			}
    			
    		]]>
    	</fx:Script>
    	<fx:Declarations>
    		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
    		<mx:HTTPService id="httpService" url="http://localhost:5025" useProxy="false" fault="onHttpServiceFault(event)" result="onHttpServiceSuccess(event)"/>
    	</fx:Declarations>
    	<mx:TextInput id="txtDataFile" text="category.xml" x="22" y="10" width="150" height="25"/>
    	<mx:Button id="btnLoadData" label="加载数据" x="192" y="10" width="130" height="25" click="loadData(event)"/>
    	<mx:Panel x="22" y="52" fontSize="12">
    		<mx:DataGrid id="dgData" width="300">
    			<mx:columns>
    				<mx:DataGridColumn headerText="类型ID" dataField="categoryID"/>
    				<mx:DataGridColumn headerText="类别名称" dataField="name"/>
    			</mx:columns>
    		</mx:DataGrid>
    	</mx:Panel>
    </s:Application>

      ②ActionScript方式

       MXML方式和AS方式的区别在于,将<mx:HTTPService/>换成使用AS来new HTTPService对象,替换的操作就是,在AS代码中声明一个HTTPService对象,并且在主Application创建完成时,对HTTPService进行初始化(creationComplete事件,类似HTML中的onload事件):

    // 首先在Application标签中添加creationComplete时间
    
    <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    			   xmlns:s="library://ns.adobe.com/flex/spark" 
    			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
    			   creationComplete="creationComplete(event)">
    
    
    // 然后在AS代码中声明一个HTTPService对象,并在creationComplete方法中对其进行初始化
    
    internal var httpService:HTTPService;
    protected function creationComplete(event:FlexEvent):void
    {
    	httpService = new HTTPService();
    	httpService.url = "http://localhost:5025";
    	// 添加事件监听,下面这种方式和最下面被注释的两行代码的方式,功能相同
    	httpService.addEventListener("fault", onHttpServiceFault);
    	httpService.addEventListener("result", onHttpServiceSuccess);
    	// httpService.addEventListener(FaultEvent.FAULT, onHttpServiceFault);
    	// httpService.addEventListener(ResultEvent.RESULT, onHttpServiceSuccess);
    }

      下面是Flex端MXML方式完整代码:

    <?xml version="1.0" encoding="utf-8"?>
    <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
    			   xmlns:s="library://ns.adobe.com/flex/spark" 
    			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
    			   creationComplete="creationComplete(event)">
    	<fx:Script>
    		<![CDATA[
    			import mx.collections.ArrayCollection;
    			import mx.controls.Alert;
    			import mx.events.FlexEvent;
    			import mx.rpc.events.FaultEvent;
    			import mx.rpc.events.ResultEvent;
    			import mx.rpc.http.HTTPService;
    			
    			internal var httpService:HTTPService;
    			
    			protected function creationComplete(event:FlexEvent):void
    			{
    				httpService = new HTTPService();
    				httpService.url = "http://localhost:5025";
    				httpService.useProxy = false;
    				httpService.addEventListener("fault", onHttpServiceFault);
    				httpService.addEventListener("result", onHttpServiceSuccess);
    				// httpService.addEventListener(FaultEvent.FAULT, onHttpServiceFault);
    				// httpService.addEventListener(ResultEvent.RESULT, onHttpServiceSuccess);
    			}
    			
    			protected function onHttpServiceFault(event:FaultEvent):void
    			{
    				Alert.show(event.message.toString());
    			}
    			
    			protected function onHttpServiceSuccess(event:ResultEvent):void
    			{
    				try {
    					var dataSource:ArrayCollection = event.result.catalog.category as ArrayCollection;
    					dgData.dataProvider = dataSource;
    				} catch(e:Error) {
    					Alert.show(event.result.toString());
    					dgData.dataProvider = null;
    				}
    			}
    			
    			protected function loadData(event:MouseEvent):void
    			{
    				var fileName:String = txtDataFile.text;
    				// 只允许加载URL同目录的文件,避免恶意加载
    				var namePassed:Boolean = fileName.indexOf('/') === -1 && fileName.indexOf('\') === -1;
    				if (namePassed) {
    					httpService.send({ filename : fileName });
    				} else {
    					Alert.show("禁止输入包含目录的路径");
    				}
    			}
    			
    		]]>
    	</fx:Script>
    	<fx:Declarations>
    		<!-- 将非可视元素(例如服务、值对象)放在此处 -->
    	</fx:Declarations>
    	<mx:TextInput id="txtDataFile" text="category.xml" x="22" y="10" width="150" height="25"/>
    	<mx:Button id="btnLoadData" label="加载数据" x="192" y="10" width="130" height="25" click="loadData(event)"/>
    	<mx:Panel x="22" y="52" fontSize="12">
    		<mx:DataGrid id="dgData" width="300">
    			<mx:columns>
    				<mx:DataGridColumn headerText="类型ID" dataField="categoryID"/>
    				<mx:DataGridColumn headerText="类别名称" dataField="name"/>
    			</mx:columns>
    		</mx:DataGrid>
    	</mx:Panel>
    </s:Application>
    

    二、服务器端监听处理

    IIS直接部署

      直接将XML文件部署到IIS上,这种方式就用不上传过去的filename了,因为IIS在接收到请求后,直接就将xml文件返回了。

    .NET自定义监听

      原理比较简单:使用Socket -> 监听指定IP的指定端口 -> 解析请求头中filename参数的值 -> 读取指定文件的内 -> 将文件数据作为响应内容进行传输 -> 关闭请求连接

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading;
    
    namespace NetRequestListener
    {
        class Program
        {
            private static Socket _serverSocket;
            static void Main(string[] args)
            {
                CreateSocket();
                Console.WriteLine("Server port 5025 is start listening..");
                ReceiveRequest();
            }
    
            /// <summary>
            /// 初始化Socket
            /// </summary>
            private static void CreateSocket()
            {
                _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _serverSocket.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.102"), 5025));
                _serverSocket.Listen(52);
            }
    
            /// <summary>
            /// 循环接收请求并处理
            /// </summary>
            private static void ReceiveRequest()
            {
                while (true)
                {
                    Socket client = _serverSocket.Accept();
                    Console.WriteLine("An client has connecting");
                    Thread th = new Thread(new ThreadStart(() =>
                    {
                        byte[] fileNameBytes = new byte[1024];
                        int len = client.Receive(fileNameBytes);
                        byte[] responseData;
                        try
                        {
                            responseData = ReadFileContent(Encoding.UTF8.GetString(fileNameBytes, 0, len));
                        }
                        catch (FileNotFoundException)
                        {
                            responseData = Encoding.UTF8.GetBytes("File not exist");
                        }
                        catch (Exception)
                        {
                            responseData = Encoding.UTF8.GetBytes("An error occurred when reading file");
                        }
                        client.Send(responseData);
                        client.Shutdown(SocketShutdown.Both);
                        client.Close();
                    }));
                    th.IsBackground = true;
                    th.Start();
                }
            }
    
            /// <summary>
            /// 根据请求中的数据读取指定文件
            /// </summary>
            /// <param name="requestData">HTTP的请求头信息</param>
            /// <returns></returns>
            private static byte[] ReadFileContent(string requestData)
            {
                // 使用正则筛选出filename参数的值
                Regex rg = new Regex("filename=(\S+)");
                string filePath = rg.Match(requestData).Groups[1].Value;
                filePath = System.Web.HttpUtility.UrlDecode(filePath);
                if (File.Exists(filePath))
                {
                    return File.ReadAllBytes(filePath);
                }
                else
                {
                    throw new FileNotFoundException();
                }
            }
        }
    }

    Node.js自定义监听

      node的代码相对要简单很多,代码很简单,就不做说明了:

    // 引入module
    var http = require('http');
    var fs = require('fs');
    var url = require('url');
    
    http.createServer(function (req, res) {
    	console.log('An client has connecting');
    	// 将请求解析为对象,取出参数部分
    	var param = url.parse(req.url, true).query;
    	var message;
    	try {
    		// 取到参数中的filename,根据filename读取指定文件,这里使用阻塞读取方式
    		message = fs.readFileSync(param.filename, 'utf-8');
    	} catch(e) {
    		if(e.code === 'ENOENT') {
    			message = 'File is not exist';
    		} else {
    			message = 'An error occurred when reading file';
    			console.log(e.message);
    		}
    	}
    	// 自定义响应头
    	res.writeHead(200, { 'content-type' : 'text/xml'});
    	// 使用end将message响应给客户端,end后会关闭连接,另有write方法,这种方式不会关闭连接
    	res.end(message);
    }).listen(5025, '192.168.1.102');
    
    console.log('Server port 5025 is start listening..');
    

      如果不想使用阻塞读取,当让也可以使用异步事件驱动:

    // 引入module
    var http = require('http');
    var fs = require('fs');
    var url = require('url');
    
    http.createServer(function (req, res) {
    	console.log('An client has connecting');
    	var param = url.parse(req.url, true).query;
    	var message;
    	fs.readFile(param.filename, {encoding : 'utf-8'}, function (err, data) {
    		if (err) {
    			if (err.code === 'ENOENT') {
    				message = 'File is not exist';
    			} else {
    				message = 'An error occurred when reading file';
    				console.log(e.message);
    			}
    		} else {
    			message = data;
    		}
    		res.writeHead(200, { 'content-type' : 'text/xml'});
    		res.end(message);
    	});
    }).listen(5025, '192.168.1.102');
    
    console.log('Server port 5025 is start listening..');
    

      

      

      


    ①:Adobe在2011年11月份已将Flex框架捐赠给Apache基金会

  • 相关阅读:
    Ubuntu 10.04安装google拼音输入法
    Ubuntu 10.04 编译Android 2.1源码
    Android make sdk 错误解决方案
    关于android内核从linux内核分支上除名
    odex打包为可用的apk程序
    取得当前屏幕的截图
    android设备作为视频监控客户端的思路
    政府网站群系统选型
    浅谈网站群的一代与二代技术
    我的2013
  • 原文地址:https://www.cnblogs.com/hourglasser/p/3541644.html
Copyright © 2011-2022 走看看