利用thrift實現js與C#通訊的例子


關鍵字:thrift js javascript C# Csharp webservice

 

1.為什么要用thrift js C#?

    1.1 首先,js 通過 thrift 訪問C#,實際上是一種c/s模式。thrift是通信工具,js是客戶端,C#是服務端。

    1.2 使用js直接與thrift server通信。讓web開發變得更簡單。如果使用Web Service,你需要自己去實現C/S兩端的序列化與反序列化操作,還需要自行處理異常,降低了開發效率。而thrift則會自動生成兩端的操作類,你只需要處理方法內部的邏輯即可。

    1.3 js直接與thrift server通信,可以提高性能,並且用C#開發server,開發效率也非常高。(那些web service弱爆了)

    1.4 當然,我們不能只看到優點。用這種方法也有比較明顯的缺點:如果使用web service,則網頁與web service可以封裝在一個工程里,部署到IIS上后,可以存在於一個網站內。而使用了thrift后,你還需要手動管理thrift程序。包括:

        1.4.1 你需要擁有服務端的絕對控制權,比如,你可以直接登錄服務器的操作系統上進行操作。因此,如果你只有一個網頁空間,則不適合這種方法。當然,你也可以用web service里綁定thrift,但這樣你又需要自己手動進行序列化與反序列操作,而且兩次轉換讓性能更低,有違初衷

        1.4.2 給thrift server程序增加自動啟動,與監視程序,來完成thrift的崩潰后自動重啟。

 

2.環境

    Win7 - VS2012 - .net 4.0 C# 控制台工程(用來承載thrift)

    Win7 - VS2012 - .net 4.0 C# Web工程(用來調試js,超方便)

 

3.步驟(以下步驟,對於小白來說,有些困難。QQ討論群:23152359 )

    3.1 去thrift官方下載thrift庫,目前是0.9.0。

    3.2 去thrift官方下載編譯好的win下的thrift編譯器,是一個exe文件。

    3.3 寫一個數據結構定義文件。我在這里只是用了服務,沒有定義自定義數據結構。

        data.txt:

1 service UserStorage
2 {
3     i32 Sum( 1: i32 arg_number1, 2: i32 arg_number2),
4     string GetString()
5 }

    3.4 命令行下,用thrift編譯器,對它進行編譯:
        run.bat:

1 thrift-0.9.0.exe --gen csharp data.txt
2 thrift-0.9.0.exe --gen js data.txt
3 pause

    3.5 建立一個名字為CSharpServer的C#控制台工程,.net 4.0的。

    3.6 為這個工程,添加現有項目:thrift庫目錄\thrift-0.9.0\lib\csharp\src\Thrift.csproj,然后引用這個項目。

    3.7 把thrift編譯出來的UserStorage.cs(在gen-csharp目錄里),拖動到解決方案管理器里的CSharpServer項目的根目錄下,UserStorage.cs與Program.cs應該在同一級。

    3.8 在CSharpServer項目里創建一個UserStorage的處理類UserStorageHandle.cs:(它應該與UserStorage.cs與Program.cs在同一級)

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 
 6 namespace CSharpServer
 7 {
 8     public class UserStorageHandle : UserStorage.Iface
 9     {
10 
11         public UserStorageHandle()
12         {
13             ;
14         }
15 
16         public int Sum(int arg_number1, int arg_number2)
17         {
18             int result = arg_number1 + arg_number2;
19             Console.WriteLine(DateTime.Now.ToString() + " 收到請求:Sum,參數:arg_number1 = " + arg_number1.ToString() + ",arg_number2 = " + arg_number2.ToString() + ",返回:result = " + result.ToString());
20             return result;
21         }
22 
23         private static int Counter = 0;
24 
25         public string GetString()
26         {
27             int currentCounter = System.Threading.Interlocked.Increment(ref UserStorageHandle.Counter);
28             Console.WriteLine(DateTime.Now.ToString() + " 收到請求:GetString,參數:沒有,返回:result = \"thrift is OK : " + currentCounter.ToString() + "\"");
29             return "thrift is OK : " + currentCounter.ToString();
30         }
31         
32     }
33 }

    3.9 主程序Program.cs:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using Thrift.Transport;
 6 using Thrift.Protocol;
 7 using Thrift.Server;
 8 using System.Net;
 9 
10 namespace CSharpServer
11 {
12     class Program
13     {
14         private static HttpListener httpListener = null;
15         private static THttpHandler httpServer = null;
16 
17         static void Main(string[] args)
18         {
19             string serviceUrl = "http://localhost:99/";
20             try
21             {
22                 UserStorageHandle handle = new UserStorageHandle();
23                 UserStorage.Processor processor = new UserStorage.Processor(handle);
24                 TProtocolFactory protocolFactory = new TJSONProtocol.Factory();
25 
26                 Program.httpServer = new THttpHandler(processor, protocolFactory);
27 
28                 Program.httpListener = new HttpListener();
29                 Program.httpListener.Prefixes.Add(serviceUrl);
30                 Program.httpListener.Start();
31                 IAsyncResult result = Program.httpListener.BeginGetContext(new AsyncCallback(WebRequestCallback), null);
32                 Console.WriteLine("Thrift 服務成功啟動,網址是 " + serviceUrl);
33             }
34             catch (System.Exception ex)
35             {
36                 Console.WriteLine("發生錯誤:" + ex.Message);
37                 Console.WriteLine("按回車鍵退出");
38                 Console.ReadLine();
39                 return;
40             }
41             Console.WriteLine("若需結束程序,請直接關閉窗口,或按回車。");
42             Console.ReadLine();
43         }
44 
45         public static void WebRequestCallback(IAsyncResult result)
46         {
47             if (Program.httpListener == null)
48             {
49                 Console.WriteLine("發生錯誤:HttpListener已經被關閉");
50                 Console.WriteLine("按回車鍵退出");
51                 Console.ReadLine();
52                 return;
53             }
54 
55             HttpListenerContext httpListenerContext = Program.httpListener.EndGetContext(result);
56 
57             Program.httpListener.BeginGetContext(new AsyncCallback(WebRequestCallback), null);
58 
59             Program.httpServer.ProcessRequest(httpListenerContext);
60         }
61 
62     }
63 }

    3.10 按F5,啟動CSharpServer項目。

    3.11 新開一個VS2012(內存不夠的趕快去買),建立一個叫JsProject的C# .net 4.0 Web空工程。

    3.12 去jquery官網下載jquery-1.9.1.js(mini版也行,隨便)

    3.13 把thrift編譯的js文件data_types.js與UserStorage.js,thrift庫的js庫文件(thrift庫目錄\thrift-0.9.0\lib\js\thrift.js),以及剛下載的jq文件jquery-1.9.1.js,全部拖動到解決方案資源管理器的JsProject項目的根目錄下:

        data_types.js \ jquery-1.9.1.js \ thrift.js \ UserStorage.js 應該與Web.config在同一級。

    3.14 在根目錄下創建一個Test.html文件,Test.html 應該與Web.config在同一級:

            Test.html:

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 5     <title></title>
 6     <script type="text/javascript" src="jquery-1.9.1.js"></script>
 7     <script type="text/javascript" src="data_types.js"></script>
 8     <script type="text/javascript" src="thrift.js"></script>
 9     <script type="text/javascript" src="UserStorage.js"></script>
10 
11     <script>
12         $(document).ready(function ()
13         {
14             var debugPosation = 0;
15             try
16             {
17                 var transport = new Thrift.Transport("http://localhost:99");
18                 var protocol = new Thrift.Protocol(transport);
19                 var client = new UserStorageClient(protocol);
20 
21                 var result_GetString = client.GetString();
22                 var result_Sum = client.Sum(255, 322);
23             }
24             catch (e)
25             {
26                 alert("出錯鳥:" + e.message);
27             }
28         });
29     </script>
30 </head>
31 <body>
32 </body>
33 </html>

    3.15 給Test.html的 “ var debugPosation = 0; ” 這一行,下斷點,然后F5,就可以看到效果了。

 

4.注意兩個問題

    4.1 由於web服務一般都是80端口,如果thrift端口與其不同,js在訪問時會遇到跨域問題,js報錯e.message = "拒絕訪問"。但是,對於傳說中的windows server,完全沒有問題,因為,windows server支持.net的傳說中的端口復用功能!因此,假設部署后,網站的iis的url為:http://www.baidu.com/XXX,則你最好給thrift server留一個二級域名,比如 http://www.baidu.com/ThriftService ,把這個留給thrift。最后,直接把thrift server的監聽url,設置為這個 http://www.baidu.com/ThriftService 就OK了,不會有端口沖突問題,因為win Server + .net 支持tcp端口復用!!!! 如果你的網站的url還帶有端口,比如 http://www.baidu.com:9999/XXX,或者IP形式:http://11.2.33.44:9999/XXX,則thriftservice也需要與它的端口相同,比如:http://www.baidu:9999/ThriftServicehttp://11.2.33.44:9999/ThriftService 。問,網站端口與thriftserver端口並不是80,而是9999,有沒有問題?答:木有問題,端口復用功能依然會發揮作用。不過,端口復用技術,是通過讓IIS和ThriftServer,把端口監聽的工作,都交給System.exe去做,所有如果要做防火牆,要注意一下。防火牆參見這個帖子:http://www.cnblogs.com/xxxteam/archive/2013/04/22/3036082.html

    4.2 網址的最后一個斜杠問題。js訪問thrift service,網址最后一個字符,是不帶斜杠的。比如http://www.baidu.com/XXX/,這個就是錯誤的,因為最后一個是斜杠。應該去掉最后一個斜杠,更正為: http://www.baidu.com/XXX  。而ThriftServer的監聽網址,則最后一個斜杠是不能省去的。坑爹吧?當然了,這個問題可能會因為日后的補丁被修正,所以大家自己留意一下。

 

5.為什么不能使用js + thrift server方案?

    看到這里傻眼了吧?上面白忙活大半天,但最后居然發現這個方案有問題?是的。

    5.1 Thrift的定義,僅僅是一個通信工具,它不是能7*24運行的類似於iis這種服務提供程序。相對於wcf來說,thrift簡單,所以高效。但正是因為它簡單,所以它缺少很多在復雜網絡環境下充當服務端的功能。在實際使用中,如果把它當成webService Server,則經常出問題。而且很多問題是try catch也抓不住,直接導致宿主程序崩潰的。所以,如果希望構建一個穩定的webService server,還是使用wcf之類的穩定方案為妙。

        不過,這並不是說thrift就不行。thrift可以在系統內部來進行數據傳輸,但絕對不能放在外部。

    5.2 js + thrift不支持異步調用!原因是,js只有以ajax方式進行遠程服務調用才具有異步功能,但thrift封裝的遠程服務調用,不是ajax方式的。

   其他更多問題詳見 http://www.cnblogs.com/xxxteam/archive/2013/04/24/3040839.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM