使用 TRESTClient 與 TRESTRequest 作爲 HTTP Client(轉) 使用 TRESTClient 與 TRESTRequest 作爲 HTTP Client

使用 TRESTClient 與 TRESTRequest 作爲 HTTP Client

 

轉自:http://www.cnblogs.com/dennieschang/p/6966403.html

 

在 Delphi XE 推出以前的年代,Delphi的展方向是筆直朝向庫連結Windows 用程式個目不斷前的,從Delphi 1開始,到Delphi 7,Delphi奠定了VB Killer的外號,主要依靠的就是與接功能超越其他開工具,而且超越的距離不只一個世代。 

在 .NET開始展,Delphi 8, Delphi .NET 不斷延候,與庫連接功能的方便性,仍然讓許多ERP廠商、硬體廠商持續愛用 Delphi.

直到 Web 開與 App 開超越了 Windows 用程式的需求,VC, VB, Delphi 也開始隨着波潮流,漸漸不再像 1990年代那麼廣受戴了。

在1990到 2010年之,Delphi的網路連線功能,主要是藉由第三方元件來提供的,其中知名度最高,全球使用人數也最多的,應該就是 Indy 套元件了。

套元件在 2000 年前,叫做 WinShose,從第八版之後才改名Indy,全球投入套元件開的開,前後超40人,從最基的 TCP/IP 功能到各種定的Client與Server 端元件,筆者從中得益非常多,也開了當中的DNS Server元件,訊協定的深入瞭解,Indy團隊是我不可或缺的師長

隨着Delphi 工具走入了多平臺開域,Indy的侷限性也在兩三年凸了出來,主要是在各個作上面於SSL與加密功能的支援無法合到作內建的功能所致。

由於個侷限性,Delphi XE6開始,REST Client系列元件漸漸開始成 Delphi 團隊的重點開發項目之一,所以我從 Delphi XE6, Delphi XE7 之後的版本,可以發現到,使用 TRESTClient, TRESTRequest, TRESTResponse 系列合的用程式越來越多了,原廠也不斷鼓勵大家使用套元件來提供 REST API 的連線功能。

REST API 的基是 HTTP 定,大多以 HTTP 的 POST 方法把 JSON 編碼形式的參數傳遞到 Server,而 Server 再以 JSON 形式的參數回

作法也會稍有化,例如以 POST 方法把 Web-Form 編碼形式的參數傳遞給 Server,Server 再以 JSON 形式把料回

形式不一而足,但相同的是 HTTP 定,最常用的也是以 POST 方法把參數傳給 Server 端。

今天要跟大家分享的主是如何『使用 TRESTClient 與 TRESTRequest 作 HTTP Client』。

 

前面已提到,在沒有 TRESTClient 整元件以前,我通常用的是 Indy 系列的元件來提供網路傳輸的功能,而在有了 TRESTClient 整元件,我在行平臺上面就可以不需要另外配置函式,也能直接使用 https 與 server 連線了,在勒索病毒泛的今天,使用 https 會使用者比安心。

POST業說

在 HTTP 的 POST 作當中,參數跟 GET 作,Client端需要以 name=value&name2=value2 種形式行字串接,再送到 Server 端去。Get 跟 POST的差異,在於 Get 方法是把所有參數當做 URL 的一部分,送 HTTP GET 指令的候,參數同 URL  一起送。

而 POST 作業則送完 POST 指令後,把所有的參數與料隨之送。依照 HTTP 型定的範,GET 作的 URL 是無法加密的,而且度也有限制。因此,當需要傳遞料比多,或者有機敏性,透 HTTPS 送,就是最直接,也最方便,更是目前最通用的料保方法。 

 POST 傳遞的參數,除了字串以外,常常包含了檔案傳遞。我很常看到在網上面以按提供使用者選擇要上的檔案,也常看提供以拖拉的方式把檔案上端系,尤其網頁郵件系最常種作法。 

去以 TIdHTTP 元件的 POST 方法送參數,呼叫方式如下:

複製代碼
 1 var
 2     httpClient : TIdHTTP;
 3     url, params, httpResultStr : string;
 4 begin
 5     url := 'http://mytestURL.com/test.php';
 6     params := 'name=我的名字&test=測試';
 7 
 8     httpClient := TIdHTTP.Create(self); 
 9     try
10          httpResultStr := httpClient.Post(url, params);
11          showMessage(httpResultStr);
12     finally
13         httpClient.Free; 
14     end; 
15 end;
複製代碼

這樣就可以把 params 字串的衆參數到 server 去了。理上是這樣,但事情並沒有簡單,在 HTTP 定當中要參數 Server,如果些字串包含了特殊字元,要先經過編碼,而編碼,是我一生都需要與之抗的繁複程序。

在 HTTP GET 方法當中,所有的參數除了要以 name=value 每一個參數做描述,以及需要用 & 來接各參數,所有的 value 都需要以 url encode 來脫 URL 保留字元的糾纏。name 是否需要編碼呢?筆者建,name 就乖乖的用英文吧,可以省下很多問題,以及些可避免的問題所需要的時間

那麼同的功能,以 TRESTClient 跟 TRESTRequest 要怎麼達成呢? 也很容易,作法如下:

1. 在 form 裏面放上 TRESTClient 跟 TRESTRequest 元件各一。

2. 把要傳遞的參數加到 TRESTRequest 體的 params 屬性裏面去,個屬性的型是 TArray,所以可以存放多參數。

3. 定 TRESTClient 要送參數的URL,注意,URL 是定在TRESTClient 哦!

4. 定 TRESTRequest 要使用的傳輸方法,要POST(因正在介的是POST方法,按照您的需求調整)

5. 呼叫 TRESTRequest 體的 execute 方法,就可以把料送去 server 了。

 

寫成 Delphi 的程式,會像以下這樣:

複製代碼
self.RESTClient1.BaseURL :=
          'http://我的網址/acceptNewCard.php';
self.RESTRequest1.Params.Clear;
self.RESTRequest1.Method := rmPOST;

self.RESTRequest1.AddParameter('test', self.EditCardNo.Text);
self.RESTRequest1.AddParameter('name', self.EditName.Text);
複製代碼

是不是很容易呢?的確很容易,裏問題等下再深入探,先來看 server 端要怎麼接收些個參數,我用 PHP 當範例,需要用 C#,JSP的者朋友們請自行轉譯喔⋯⋯

 

PHP Server 端接收 POST 參數的方法

從 1994 年開始,筆者就陸續撰文明 HTTP POST 方法如何接參數,包含了CGI 用C,perl等作,也包含 ISAPI 以 Delphi 作,近幾年比流行的是 PHP,JSP,C#,但 PHP 程式碼讀起來比較簡潔易懂,所以我就選擇 PHP 來做範例了。 

在 PHP 裏面,透GET 跟 POST 方法傳遞的參數,會被分存放在 $_GET 跟 $_POST 兩個數裏面,如果要偷懶,不想區分 GET 或 POST 方法,也可以從 $_REQUEST 取,當中有些安全性考量,最好勤一點,把它區分開來。

 

剛剛的例子來看,我們傳了一個名 name,以及一個名 test 的字串,用的是 POST 方法,所以我得用以下兩個數來存取兩個字串:

•  $_POST['name']  數可以取得 Client 端送出來的 name 

•  $_POST['test']  數可以取得 Client 端送出來的 test

所以在 server 端,我可以這樣寫,來抓到兩個料:

$name = $_POST["name"];

$test = $_POST["test"];

 

這樣寫會不會出問題呢? 答案是不會!如果使用者不入中文的

 

中文料的編碼處

Delphi的開員絕大多數都是英美系的人,我推因此系的文字示與傳輸沒有法完整的測試,但於我以中文的人來,從電腦誕生的那個年代,中文的示在每個操作、每種通訊協定的設計都比英文來的困

以上面的例子來看,如果我直接拿個例子來測試,筆者寫的範例程式,傳輸資,Server 所抓到的文字並不是正確的中文字,如下所示:              

  

可以看得出來,到 server 的候,server 是不到資訊的。是怎麼回事呢?筆者屬於不認輸的好奇寶寶,使出了身解數,於解決了問題

 

 Web 程式的一定可以立刻推出來,這絕對是文字編碼問題了,然而,是什麼地方出問題?可能出問題的點我列出來跟大家分享:

•  HTTP Client 的 charset 

•  HTTP Request 裏面的文字編碼問題

檢查的方向也是從兩個關點出,第一點的檢測很容易,從Object Inspector檢查一下 RESTRequest1的定:

AcceptCharset 確定是 UTF-8,沒,所以定不是問題

接着,就要從 Client 端出去的料下手了。有者或『你怎麼不疑Server端程式寫了?』問題很好,之所以排除了問題,是因同一個 Server 端的 PHP 程式,我用了 Postman 做對測試,回果是正確的,因此判定是 Client 端程式的問題

接着筆者從 TRESTRequest.AddParameter 的各種多形式來嘗試,AddParameter 個方法有以下幾種多的形式:

procedure AddParameter(const AName, AValue: string); overload;
procedure AddParameter(const AName: string; AJsonObject: TJSONObject; AFreeJson: boolean = true); overload;
procedure AddParameter(const AName, AValue: string; const AKind: TRESTRequestParameterKind); overload;

三種形式我都測試過,從 AddParameter 的行中 trace 去看各個可能性,由於 TRESTRequest 的參數中,Get 跟 Post 的加入方法是混用的,在程式裏面編碼又會有點不同。

在 REST.Client.pas 裏面,我曾經懷過編碼錯誤,所以也在各個數都察,最後,找到了原因與解法,至於程,就不多了,花了我兩天咧。

原因:編碼錯誤

用HTTP傳遞中文的候,必用UTF-8編碼,但一定要得,中文字在作中,都是UCS32編碼象在Windows裏面如此,在Android裏面如此,在iOS跟Mac我不確定,但理方法是一的。 

直接以 AddParameter('name', '中文測試'); 把參數加 TRESTRequest 候,REST.Client.pas 的程式是把 '中文測試個字串直接抓 Ord 的料來做編碼的,然而,個作法,是的!!!!!!!! 

在 HTTP 傳遞 UTF-8 料的候,我傳遞的是 UTF-8 文字的二料,但直接把 '中文測試個字串直接拿來成二位? 當時編碼並不是 UTF-8 啊,當然怎麼編碼送到 server 都是的!!!!

解法:AddParameter之前先做 UTF-8 轉換

個解法,筆者第一天就已想到,只是很想像以前改 Indy 程式一,直接改好 REST.Client.pas 之後,回饋給原廠使用,所以花了不少時間找方法,最後發現這個方法不用到 REST.Client.pas,又能正確理,就直接麼跟大家分享了,寫成 Delphi 程式如下:

複製代碼
var
     nameStr : String;
begin
   ...
   nameStr := TIdURI.ParamsEncode(nameStr, IndyTextEncoding_UTF8);
   self.RESTRequest1.AddParameter('name', nameStr,      
             TRESTRequestParameterKind.pkGETorPOST,     
             [TRESTRequestParameterOption.poDoNotEncode]);
   ... 
end;
複製代碼

在把字串透 AddParameter 加入參數列之前,我先把字串做個 UTF-8 轉換,在裏用的是 TIdURI 的類別方法 ParamsEncode,個方法只有兩個參數,第一個參數是字串內容,第二個參數是要文字編碼的種,在裏我選擇了 UTF8,寫法就是上面範例程式的第一行。

接着,在呼叫 AddParameter 的候,我使用了多形式當中的第三種,要求 AddParameter 料的候不要再我的編碼,因我已經處理好了。

這麼修改過之後,在各個作業系統當中,執行結果都是正確的,上面兩個圖以 Windows 作業系統爲例,現在我們拿 Android 截圖來做爲例子:

 

者可以看到右的截裏面,server 回料已是正確的中文字了。

最後,我把 PHP 程式也附上來大家參考:

複製代碼
 1 <?php
 2 date_default_timezone_set("Asia/Taipei");
 3 header('Content-Type: charset=utf-8');
 4 
 5 include("public/DBClassPDO.php");
 6 $objDBPDO = new DBClassPDO();
 7 
 8 $cardNum = $_POST["cardNum"];
 9 $floorIdx = $_POST["floorIdx"];
10 $name = $_POST["name"];
11 $houseNum = $_POST["houseNum"];
12 
13 $params = array();
14 $params['name'] = $name;
15 $params['cardno'] = $cardNum;
16 $params['houseNum'] = $houseNum;
17 $params['floorIdx'] = $floorIdx;
18 $params['picFilename'] = $fileSaveName;
19 $params['created'] = 0;
20 
21 $result["resultCode"] = "0";
22 $result["result"] = "成功"; 
23 $result["sqlcmd"] = $name;
24 
25 $jsonStr = json_encode($result);
26 echo $jsonStr;
27 ?>
複製代碼

是最基本的傳遞字串,下次再大家示範怎麼檔案,透 TRESTRequest來做也是很簡單的,TRESTRequest 跟 TRESTClient 的確是取代 TIdHTTP 的好工具。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章