使用微軟的 C++ REST SDK

programmer_lin發表於2013-12-21

MSDN官網簡介:藉助 C++ REST SDK(代號“Casablanca”),您可以更輕鬆地編寫與基於雲端的服務相連的新式非同步 C++ 程式碼。

新的SDK讓你可以在C++中使用REST服務

Visual Studio 2013中包括了C++ REST SDK version 1.0(也稱為Casablanca)。這個微軟的開源專案包括在CodePlex中,這個專案同時也利用了c++11中的新特點,設計了現代、非同步、多平臺API,從而簡化了基於雲端的程式設計。這是兩篇關於C++ REST SDK系列文章的第一篇,我會介紹如何通過SDK來使用REST服務。在下一篇文章中,我將介紹怎樣利用SDK來檢索和傳送JSON檔案。

 

理解C++ REST SDK結構

當你需要最佳效能時,你往往會在本地進行評估,那麼C++就是最佳選擇之一。微軟認為C++在雲端也是很有價值的,微軟最新的C++ REST SDK使得開發者可以通過C++來呼叫REST服務,從而滿足高效能和可擴充套件的要求。它讓你在C++中就可以呼叫REST服務或者是編寫其他與雲端計算相關的程式碼。

如果你正在使用C++來呼叫雲端服務,但是你在回撥函式中使用基於C語言的同步API,那麼你沒用充分利用最新C++版本的高明之處。同時,你的程式碼可能會很難閱讀和除錯,同步的API使得你很難設計一個反應敏捷的使用者介面(UI)。大部分現代的WEB API都儘量減少不必要的樣板,並且提供非同步方法。這些方法避免了C風格的回撥函式的複雜性。

比如,你正在使用C++ 11,但是你利用它,通過呼叫一個同步的基於C的API,來進行HTTP的GET呼叫,那麼這樣做的效率是不能和其他程式語言比如C#、Python相提並論的。微軟基於並行模式庫PPL研發了C++ REST SDK,並且利用了PPL的基於任務程式設計模型。無論何時,你利用C++ REST SDK執行非同步操作,你都建立了一個新的PPL任務。為了讓C++ REST SDK可以移植到Linux平臺上,微軟確保PPL的關鍵部分可以在Linux上執行(並且使用GCC編譯)。因此,C++ REST SDK為依賴C++ 11的C++提供了一個併發執行環境。不同於使用回撥函式,你可以優雅地編寫C++11標準的程式碼來建立任務並且在其他任務執行完畢後,排程任務。如果你之前有過PPL的程式設計經驗,你會發現使用C++ REST SDK非常簡單。

C++ REST SDK基於如下的四個底層棧或是API,這些棧或是API是基於不同作業系統提供的服務。(見Figure1)

  • WinHTTP:也稱為Microsoft Windows HTTP Services. 這是一個基於C語言的HTTP客戶端API。
  • PPL( Parallel Patterns Library的簡稱): 構成非同步操作的程式設計模型。C++ REST SDK 在不同的Windows版本中使用WinHTTP 。
  • Boost.Asio: 跨平臺的C++庫,可以用於網路程式設計或是底層的I/O程式設計。它提供了一致的非同步模型。該庫採用現代C++方法。 C++ REST SDK 使用Boost.Asio 在Linux平臺上管理通訊。
  • HTTP.sys: Windows 伺服器端的HTTP。C++ REST SDK 在不同的Windows版本中使用 HTTP.sys。

C++REST_01
目前(寫成本文時),C++ REST SDK支援以下作業系統。特別注意,對Windows XP 系統和Windows Phone 8.x系統的支援,還在試驗階段。

  • Windows XP
  • Windows Vista
  • Windows 7
  • Windows 8.x
  • Windows Phone 8.x
  • Linux

C++ REST SDK還包括如下部分,這些功能使用了不同的底層棧(見Figure 2):

  • Asynchronous streams and stream buffers(非同步流和流緩衝區):這部分提供了一種基本的非同步流,一種基本的非同步流緩衝區,以及許多實現,比如非同步檔案流。有一些特定的互操作流,可以支援STL iostreams和C++ REST SDK非同步流之間的互相操作。
  • HTTP client and listener(HTTP客戶端與監聽):HTTP客戶端允許你獲得與HTTP服務的連線,並且向伺服器傳送請求。 HTTP監聽讓你可以從指定的URI接收資訊。
  • JSON parser and writer(JSON解析和寫入): JSON對於像C++之類的靜態語言是一個挑戰。 C++ REST SDK 中使用一個單獨的類(web::json::value)來表示JSON值,並且提供了必要的操作來幫助資料序列化 。你可以在程式碼執行階段,宣告與JSON數值相關的型別。 C++ REST SDK 允許你通過JSON解析從流中讀取JSON資料,以及向流中寫入JSON資料。
  • TCP client and listener(TCP客戶端與監聽):TCP客戶端為TCP網路服務提供了客戶端連線。TCP監聽會持續監聽TCP客戶端的網路連線。TCP客戶端與監聽的最大優勢在於,可以完成非阻塞非同步操作。但是,這些元件仍然在實驗階段。如果你要使用System.Net.Sockets::TcpListener或者System.Net.Sockets::TcpClient類,你要適應使用實驗版的TCP客戶端和監聽,以及它們提供的簡單的非阻塞非同步操作。

C++REST_02

微軟的C++ REST SDK團隊計劃在不久的將來,在系統中增加如下部分:

  • Web Sockets client and listener. WEB Socket客戶端與箭筒
  • UDP client and listener. UDP 客戶端與監聽
  • Additional product-specific APIs built on top of the C++ REST SDK, such as Azure Storage, Mobile Services, and Bing Maps. 基於C++ REST SDK的其他產品專用API,比如Azure儲存,移動服務和Bing地圖。

 

在Visual Studio 工程中使用C++ REST SDK

在Visual Studio中建立使用SDK的專案並且成功生成該專案,你需要從CodePlex(http://casablanca.codeplex.com/)下載並安裝最新的SDK。在本文中,使用的是1.3版本。如果你下載的不是這一版本,你要在相應的配置值上做出調整。

版本1.3中預設的安裝資料夾是C:\Program Files (x86)\Microsoft Cpp REST SDK for VS 2013 v1.3\SDK.VSProject子資料夾下有兩個屬性檔案與你的Visual Studio工程相對應:CppRest.propsandversion.props.

當你在Visual Studio中建立了你準備使用C++ REST SDK的工程之後,你必須按照下列步驟操作:

  • 將C++ REST SDK安裝資料夾下的兩個屬性檔案,即VSProject子資料夾中的CppRest.props以及version.propswe檔案,複製到你建立Visual Studio專案的主資料夾中。
  • 開啟cpprest.props屬性檔案,其中的兩個屬性問價可能有錯誤值:CppRestSDKPathandCppRestRuntimeBaseFileName.如下圖所示,如果你找到了下面的兩行,你要將其中110替換為120。在64-bit的Windows版本中,規定了C++ REST SDK基本安裝資料夾的屬性值是InstallDir,這個屬性值在HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\CppRestSDK\OpenSourceRelease\120\v1.3\SDK中.不幸的是,一些SDK版本不會檢查屬性值,如果你不用上述的120替換掉110這個值,就不能成功生成對應工程。因為,不替換對應值的話,在生成專案的過程中,找不到正確的登錄檔入口。C++ REST SDK中提供的樣例,也存在這樣的問題,因此你必須在屬性檔案中替換相應值,才能正確生成專案檔案。

未修改屬性檔案:

修改後的屬性檔案:

 

  • 現在,開啟在你喜歡的文字編輯器中,開啟你的C++專案對應Visual Studio 中的vcxproj檔案,在Project中加入下面一行。這樣,你的專案就可以包含CppRest.props中的定義。值得注意的是,CppRest.props中有一行是引入已經拷貝的CppRest.props配置檔案:<Import Project=”CppRest.props” />
  • Visual Studio中開啟對應專案,開啟專案屬性。在Configuration Properties | VC++ Directories中的include Directories屬性中加入C++ REST SDK安裝路徑下include子資料夾的完整路徑。如果你使用的是預設安裝資料夾,你需要新增的屬性值為C:\Program Files (x86)\Microsoft Cpp REST SDK for VS 2013 v1.3\SDK\include
  • Configuration Properties | VC++ DirectoriesLibrary Directories屬性中加入C++ REST SDK安裝路徑下lib子資料夾的完整路徑.如果你使用的是預設安裝資料夾,那麼你需要新增的屬性值為C:\Program Files (x86)\Microsoft Cpp REST SDK for VS 2013 v1.3\SDK\lib.
  • 新增C++ REST SDK庫。具體來說,在Configuration Properties | Linker | Input中的Additional Dependencies加入cpprest120d_1_3.lib檔案。

現在,你的C++專案就可以開始和C++ REST SDK一起工作了。(你也可以在 Package Manager Console控制檯,通過執行命令Install-Package cpprestsdk來安裝最新版本的C++ REST SDK,同時,使用相應包來向已經建立的專案新增C++ REST SDK並完成相應設定。但是,在新專案中使用最新版本SDK的最佳方法,是按照上文所述的步驟進行配置和新增。)

 

通過引數執行一個非同步的HTTP GET呼叫

下面的程式碼說明了一個Windows控制檯應用程式,通過C++ REST SDK呼叫Flickr。這個例子使用了一個HTTP GET呼叫:http://api.flickr.com/services/rest/method=flickr.test.echo&name=value,並且檢索由伺服器返回的狀態程式碼,返回報頭型別和長度,以及返回主體報文。(在使用這些程式碼之前,你需要按照前面描述的步驟配置你的Visual Studio專案。)

程式碼:

程式碼中的wmain方法在Windows 中稱為HTTPGetAsync方法,這個方法返回一個pplx::task<void>例項來表示一個非同步操作。在這個例子中,程式碼呼叫wait方法來處理返回的例項,因為在這個示例控制檯應用中,只要列印出結果即可。但是,一般來說,你可能不會呼叫wait來處理返回的例項,這樣不會阻塞UI操作。

HTTPGetAsync方法建立一個新的web::http::client:http_client例項,從而保持與Flickr REST API的連線,其中Flickr REST API的URI是http://api.flickr.com/services/rest/.The C++ REST SDK使用獨立於平臺的字串,所以為了按照不同平臺的方式處理字元,程式碼中使用了U(str)巨集來取字串常量並且轉化為與平臺相應的型別。typedef utility::string_t對應的就是平臺的特點。

http_client client(U(“http://api.flickr.com/services/rest/”));

在這一句中,程式碼指定了客戶端並且決定了請求對應的URI。其中的路徑為/services/rest,它已經包含在用於建立HTTP客戶端的URI中了。因此,不需要特別指定這個路徑。程式碼中建立了web::http::uri::builder類的例項,從而允許你用增量的方式建立URIs。這是一種方便而優雅的方法來追加查詢片段(通過使用U(str)巨集)。兩個呼叫append_query方法增加了必要的對URI生成器的查詢,並首先將它們編碼。然後,為生成器呼叫to_string方法,生成必要的查詢片段來完成請求。

下面的程式碼是初始化模組用於建立請求並且返回結果task例項來代表非同步操作。request方法表明,它需要建立一個HTTPGET請求(methods::GET),同時需要附加查詢片段(path_query_fragment)。值得注意的是,then這個方法為執行的請求新增了一個延續的task。這樣,延續的任務可以在任務執行之後,將http_response例項作為一個引數接收。因此,then之後的程式碼就會後自行一個新的task,並且檢查請求結果。如果你度過同步程式碼的話,這裡的程式碼也很容易閱讀。很容易看見,在請求task完成之後,程式碼會被阻塞,直到then執行完畢。你不需要研究複雜的流程,你可以使用then來連線許多工並且加上需要執行的程式碼。

在本例中,then這個部分中定義的程式碼是為了展現從伺服器端返回的狀態碼,頭部內容的型別和長度。將http_response作為後一個任務的引數接收,使得一切都易於訪問。

這裡,簡單的Flickr API呼叫,返回的XML如下所示。本例只是想介紹如何通過引數建立一個簡單的HTTP GET請求,並且用C++ REST SDK處理返回結果。

處理返回結果的程式碼使用了一個流,來從請求中讀取資料。本例中,為了簡單,程式碼呼叫了read_to_end方法並且連續呼叫了一個get方法來等待任務中程式碼執行的結果。read_to_end會先定位到流的尾部,再開始讀取,然後返回一個task<size_t>來說明讀入的字元數。因此,你可以非同步呼叫read_to_end方法,並且呼叫另一個task來處理then中返回的結果。在本例中,get方法等待任務完成,並且返回任務產生的結果。值得注意的是,當task是一個取消命令時,呼叫該方法會丟擲task_canceled異常。一般來說,如果你另一個任務中的話,一般不會使用get(也是為了避免阻塞UI)。

正如你從本例中看到的那樣,使用C++11和C++ REST SDK執行一個簡單的HTTP GET請求相當簡單。then使得理解非同步呼叫順序變得簡單,C++ REST SDK中不同的幫助使得必要的樣板程式碼很少。

在下一篇文章中,我會提供一個複雜的例子,來說明如何高效使用C++ REST SDK及其幫助和典型的非同步操作,來檢索和傳送JSON資料。另外,我會介紹怎樣使用非同步流,以及其他REST服務中常用的HTTP方法。

相關文章