13.13 Web Services協議腳本應用-選自<<精通軟件性能測試與LoadRunner最佳實戰>>
13.13.1 Web Services簡介
Web Service是基於網絡的、分布式的模塊化組件,它執行特定的任務,遵守具體的技術規范,這些規范使得Web Service能與其他兼容的組件進行互操作。Internet Inter-Orb Protocol(IIOP)都已經發布了很長時間了,但是這些模型都依賴於特殊對象模型協議,而Web Services利用SOAP和XML對這些模型在通信方面作了進一步的擴展以消除特殊對象模型的障礙。Web Services主要利用HTTP和SOAP協議使商業數據在Web上傳輸,SOAP通過HTTP調用商業對象執行遠程功能調用,Web用戶能夠使用SOAP和HTTP通過Web調用的方法來調用遠程對象。
客戶根據WSDL描述文檔,會生成一個SOAP請求消息,請求會被嵌入在一個HTTP POST請求中,發送到Web服務器來。Web Services部署於Web服務器端,Web服務器把這些請求轉發給Web Services請求處理器。請求處理器解析收到的請求,調用Web Services,然后再生成相應的SOAP應答。Web服務器得到SOAP應答后,會再通過HTTP應答的方式把信息送回到客戶端。
下面針對Web Services中的一些重要名詞進行講解。
(1)UDDI,英文為“Universal Description, Discovery and Integration”,可譯為“通用描述、發現與集成服務”。UDDI是一個獨立於平台的框架,用於通過使用Internet來描述服務,發現企業,並對企業服務進行集成。任何規模的行業或企業都能得益於UDDI,UDDI使用W3C和IETF*的因特網標准,比如XML、HTTP和DNS協議。在UDDI之前,還不存在一種Internet標准,可以供企業為它們的企業和伙伴提供有關其產品和服務的信息。也不存在一種方法,來集成到彼此的系統和進程中。那么UDDI有什么樣的用途呢?舉個例子來講,假如航空行業發布了一個用於航班預訂的UDDI標准,航空公司就可以把它們的服務注冊到一個UDDI目錄中。然后旅行社就能夠搜索這個UDDI目錄以找到航空公司預訂界面。當此界面被找到后,旅行社就能夠立即與此服務進行通信,這是由於它使用了一套定義良好的預訂界面。
(2)WSDL英文為“Web Services Description Language”,可譯為網絡服務描述語言。它是一種使用XML編寫的文檔,可描述某個Web Service。它可規定服務的位置,以及此服務提供的操作(或方法)。WSDL文檔僅僅是一個簡單的XML文檔,它包含一系列描述某個Web Service的定義。
以下WSDL文檔的簡化的片段是后續將會講到的,這里我們先拿出來分析一下:
<message name="getTermRequest">
<part name="term" type="xs:string"/>
</message>
<message name="getTermResponse">
<part name="value" type="xs:string"/>
</message>
<portType name="glossaryTerms">
<operation name="getTerm">
<input message="getTermRequest"/>
<output message="getTermResponse"/>
</operation>
</portType>
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:xs="http://www.w3.org/2001/XMLSchema" name="IMyHelloservice"
targetNamespace="http://tempuri.org/" xmlns:tns="http://tempuri.org/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/">
<message name="Welcome0Request">
<part name="name" type="xs:string" />
</message>
<message name="Welcome0Response">
<part name="return" type="xs:string" />
</message>
<portType name="IMyHello">
<operation name="Welcome">
<input message="tns:Welcome0Request" />
<output message="tns:Welcome0Response" />
</operation>
</portType>
<binding name="IMyHellobinding" type="tns:IMyHello">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="Welcome">
<soap:operation soapAction="urn:MyHelloIntf-IMyHello#Welcome" style="rpc" />
<input message="tns:Welcome0Request">
<soap:body use="encoded" encodingStyle=http://schemas.xmlsoap.org/soap/encoding/
namespace="urn:MyHelloIntf-IMyHello" />
</input>
<output message="tns:Welcome0Response">
<soap:body use="encoded" encodingStyle=http://schemas.xmlsoap.org/soap/encoding/
namespace="urn:MyHelloIntf-IMyHello" />
</output>
</operation>
</binding>
<service name="IMyHelloservice">
<port name="IMyHelloPort" binding="tns:IMyHellobinding">
<soap:address location="http://localhost:5678/soap/IMyHello" />
</port>
</service>
</definitions>
我們可以將該WSDL 文檔分成三部分。
第一部分:聲明部分內容
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:xs="http://www.w3.org/2001/XMLSchema" name="IMyHelloservice"
targetNamespace="http://tempuri.org/" xmlns:tns="http://tempuri.org/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/">
第二部分:
<message name="Welcome0Request">
<part name="name" type="xs:string" />
</message>
<message name="Welcome0Response">
<part name="return" type="xs:string" />
</message>
<portType name="IMyHello">
<operation name="Welcome">
<input message="tns:Welcome0Request" />
<output message="tns:Welcome0Response" />
</operation>
</portType>
<binding name="IMyHellobinding" type="tns:IMyHello">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="Welcome">
<soap:operation soapAction="urn:MyHelloIntf-IMyHello#Welcome" style="rpc" />
<input message="tns:Welcome0Request">
<soap:body use="encoded" encodingStyle=http://schemas.xmlsoap.org/soap/encoding/
namespace="urn:MyHelloIntf-IMyHello" />
</input>
<output message="tns:Welcome0Response">
<soap:body use="encoded" encodingStyle=http://schemas.xmlsoap.org/soap/encoding/
namespace="urn:MyHelloIntf-IMyHello" />
</output>
</operation>
</binding>
在這部分內容中,<portType> 元素把 " IMyHello" 定義為某個端口的名稱,把 " Welcome " 定義為某個操作的名稱。操作 " Welcome " 擁有一個名為 " Welcome0Request " 的輸入消息,以及一個名為 " Welcome0Response " 的輸出消息。<message> 元素可定義每個消息的部件,以及相關聯的數據類型。從上面的文檔您不難發現,其主要有以下元素的元素來描述某個web service ,參見表13-5。
表13-5 WSDL 文檔結構表
元 素 |
定 義 |
<portType> |
Web Service 執行的操作 |
<message> |
Web Service 使用的消息 |
<types> |
Web Service 使用的數據類型 |
<binding> |
Web Service 使用的通信協議 |
<portType> 元素是最重要的WSDL元素。它可描述一個 Web Service、可被執行的操作,以及相關的消息。可以把<portType>元素比作傳統編程語言中的一個函數庫(或一個模塊、或一個類)、<message>元素定義一個操作的數據元素。每個消息均由一個或多個部件組成。可以把這些部件比作傳統編程語言中一個函數調用的參數、<types>元素定義Web Service使用的數據類型。為了最大程度的平台中立性,WSDL使用XML Schema語法來定義數據類型、<binding>元素為每個端口定義消息格式和協議細節。binding元素的name屬性定義binding的名稱,而type屬性指向用於binding的端口,在這個例子中是“ImyHello”端口。
soap:binding元素的style屬性可取值“rpc”或“document”。在這個例子中我們使用rpc、transport屬性定義了要使用的SOAP協議,在這個例子中我們使用HTTP。operation元素定義了每個端口提供的操作符,對於每個操作,相應的SOAP行為都需要被定義。同時您必須對輸入和輸出進行編碼。在這個例子中我們使用了“encoded”。
第三部分:
<service name="IMyHelloservice">
<port name="IMyHelloPort" binding="tns:IMyHellobinding">
<soap:address location="http://localhost:5678/soap/IMyHello" />
</port>
</service>
service是一套<port>元素。在一一對應形式下,每個<port>元素都和一個location關聯。如果同一個<binding>有多個<port>元素與之關聯,可以使用額外的URL地址作為替換。
一個WSDL文檔中可以有多個<service>元素,而且多個<service>元素十分有用,其中之一就是可以根據目標URL來組織端口。這樣,我就可以方便地使用另一個<service>來重定向我的股市查詢申請。我的客戶端程序仍然工作,因為這種根據協議歸類的服務不隨服務而變化。多個<service>元素的另一個作用是根據特定的協議划分端口。例如,我可以把所有的HTTP端口放在同一個<service>中,所有的SMTP端口放在另一個<service>里。
13.13.2 Delphi Web Services樣例程序
1.服務端
為了使讀者朋友對Web Services程序的開發過程有一個較清晰的認識,這里作者用Delphi給大家做一個簡單樣例程序。服務端用來提供對外服務接口,只有服務端運行后,其提供的服務接口才能被其他應用所調用,這里我們把調用其服務接口的程序統一叫客戶端。
首先,選擇“SOAP Server Application”選項,如圖13-110所示。
單擊【OK】按鈕,則彈出圖13-111所示對話框信息,我們選擇 “ISAPI/NSAPI Dynamic Link Library”,單擊【OK】按鈕,彈出確認對話框,如圖13-112所示,單擊【Yes】按鈕。
圖13-110 New Items對話框 圖13-111 New SOAP Server Application對話框 圖13-112 Confirm對話框
將出現圖13-113所示界面信息,您可以在對話框中輸入服務名稱,這里我們將該服務接口定義為“MyHello”,單擊【OK】按鈕,將產生相關的單元(Unit)文件,下面將附上相關文件的源代碼供大家參考。
圖13-113 Confirm對話框 圖13-114 WebModule1對話框(對應單元文件為main.pas)
main.pas源代碼:
{ SOAP WebModule }
unit main;
interface
uses
SysUtils, Classes, HTTPApp, InvokeRegistry, WSDLIntf, TypInfo,
WebServExp, WSDLBind, XMLSchema, WSDLPub, SOAPPasInv, SOAPHTTPPasInv,
SOAPHTTPDisp, WebBrokerSOAP;
type
TWebModule1 = class(TWebModule)
HTTPSoapDispatcher1: THTTPSoapDispatcher;
HTTPSoapPascalInvoker1: THTTPSoapPascalInvoker;
WSDLHTMLPublish1: TWSDLHTMLPublish;
procedure WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
WebModule1: TWebModule1;
implementation
{$R *.dfm}
procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
WSDLHTMLPublish1.ServiceInfo(Sender, Request, Response, Handled);
end;
end.
MyHelloImpl.pas源代碼:
unit MyHelloImpl;
interface
uses InvokeRegistry, Types, XSBuiltIns, MyHelloIntf;
type
{ TMyHello }
TMyHello = class(TInvokableClass, IMyHello)
public
function Welcome(name: string): string; stdcall;
end;
implementation
function TMyHello.Welcome(name: string): string;
begin
result := '歡迎' + name + '同學!' ;
end;
initialization
{ Invokable classes must be registered }
InvRegistry.RegisterInvokableClass(TMyHello);
end.
MyHelloIntf.pas源代碼:
unit MyHelloIntf;
interface
uses InvokeRegistry, Types, XSBuiltIns;
type
TEnumTest = (etNone, etAFew, etSome, etAlot);
TDoubleArray = array of Double;
TMyEmployee = class(TRemotable)
private
FLastName: AnsiString;
FFirstName: AnsiString;
FSalary: Double;
published
property LastName: AnsiString read FLastName write FLastName;
property FirstName: AnsiString read FFirstName write FFirstName;
property Salary: Double read FSalary write FSalary;
end;
{ Invokable interfaces must derive from IInvokable }
IMyHello = interface(IInvokable)
['{F80D3129-3B13-49A7-8CCF-3DC3B120BA15}']
{ Methods of Invokable interface must not use the default }
{ calling convention; stdcall is recommended }
function Welcome(name: string): string; stdcall;
end;
implementation
initialization
{ Invokable interfaces must be registered }
InvRegistry.RegisterInterface(TypeInfo(IMyHello));
end.
接下來,您需要創建一個標准的“Application”,界面信息如圖13-115所示。
圖13-115 樣例演示-服務端(對應單元文件為u_main.pas)
u_main.pas源代碼:
unit u_main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, SUIButton, StdCtrls, ExtCtrls, SUIForm, IdHTTPWebBrokerBridge;
type
TForm1 = class(TForm)
sfrm1: TsuiForm;
lbl1: TLabel;
btn1: TsuiButton;
procedure btn1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure sfrm1Click(Sender: TObject);
private
{ Private declarations }
ser: TIdHTTPWebBrokerBridge;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses main, MyHelloImpl, MyHelloIntf;
{$R *.dfm}
procedure TForm1.btn1Click(Sender: TObject);
begin
close;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ser:=TIdHTTPWebBrokerBridge.Create(self);
ser.DefaultPort:=5678;
ser.Active:=true;
ser.RegisterWebModuleClass(TWebModule1);
end;
end.
Server.dpr源代碼:
program Server;
uses
Forms,
u_main in 'u_main.pas' {Form1},
main in 'main.pas' {WebModule1: TWebModule},
MyHelloImpl in 'MyHelloImpl.pas',
MyHelloIntf in 'MyHelloIntf.pas';
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TWebModule1, WebModule1);
Application.Run;
end.
所有源代碼編寫完成后,單擊“F9”運行程序,將彈出圖13-116所示界面。
如圖13-116所示,“樣例演示-服務端”小程序運行后,您可以打開IE,輸入“http://localhost:5678/”來檢驗先前完成的服務是否可以成功展示,如圖13-117所示。
圖13-116 “樣例演示-服務端”小程序 圖13-117 服務接口相關信息
2.客戶端
最后,讓我們來制作一個客戶端小程序來調用先前完成的接口。
創建一個標准的Delphi應用,其界面設計如圖13-118所示。
應用“WSDL Import Wizard”工具引入接口,如圖13-119和圖13-120所示。
圖13-119 “New Items-WSDL Importer”對話框 圖13-120 “WSDL Import Wizard”對話框
引入服務接口后,將生成“IMyHello1.pas”單元文件,其源代碼如下:
// ************************************************************************ //
// The types declared in this file were generated from data read from the
// WSDL File described below:
// WSDL : http://localhost:5678/wsdl/IMyHello
// Encoding : utf-8
// Version : 1.0
// (2012-11-11 下午 02:02:42 - 1.33.2.5)
// ************************************************************************ //
unit IMyHello1;
interface
uses InvokeRegistry, SOAPHTTPClient, Types, XSBuiltIns;
type
// ************************************************************************ //
// The following types, referred to in the WSDL document are not being represented
// in this file. They are either aliases[@] of other types represented or were referred
// to but never[!] declared in the document. The types from the latter category
// typically map to predefined/known XML or Borland types; however, they could also
// indicate incorrect WSDL documents that failed to declare or import a schema type.
// ************************************************************************ //
// !:string - "http://www.w3.org/2001/XMLSchema"
// ************************************************************************ //
// Namespace : urn:MyHelloIntf-IMyHello
// soapAction: urn:MyHelloIntf-IMyHello#Welcome
// transport : http://schemas.xmlsoap.org/soap/http
// style : rpc
// binding : IMyHellobinding
// service : IMyHelloservice
// port : IMyHelloPort
// URL : http://localhost:5678/soap/IMyHello
// ************************************************************************ //
IMyHello = interface(IInvokable)
['{FEDC3D83-ACE9-0403-6D1D-C1B54AA0B54C}']
function Welcome(const name: WideString): WideString; stdcall;
end;
function GetIMyHello(UseWSDL: Boolean = System.False; Addr: string = ''; HTTPRIO: THTTPRIO
= nil): IMyHello;
implementation
function GetIMyHello(UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): IMyHello;
const
defWSDL = 'http://localhost:5678/wsdl/IMyHello';
defURL = 'http://localhost:5678/soap/IMyHello';
defSvc = 'IMyHelloservice';
defPrt = 'IMyHelloPort';
var
RIO: THTTPRIO;
begin
Result := nil;
if (Addr = '') then
begin
if UseWSDL then
Addr := defWSDL
else
Addr := defURL;
end;
if HTTPRIO = nil then
RIO := THTTPRIO.Create(nil)
else
RIO := HTTPRIO;
try
Result := (RIO as IMyHello);
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := defSvc;
RIO.Port := defPrt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
end;
initialization
InvRegistry.RegisterInterface(TypeInfo(IMyHello), 'urn:MyHelloIntf-IMyHello', 'utf-8');
InvRegistry.RegisterDefaultSOAPAction(TypeInfo(IMyHello),
'urn:MyHelloIntf-IMyHello#Welcome');
end.
.Unit1.pas源代碼:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, SUIButton, ExtCtrls, SUIForm, StdCtrls, SUIEdit;
type
TForm1 = class(TForm)
sfrm1: TsuiForm;
btn1: TsuiButton;
lbl1: TLabel;
edt1: TsuiEdit;
btn2: TsuiButton;
lbl2: TLabel;
lbl3: TLabel;
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses IMyHello1;
{$R *.dfm}
procedure TForm1.btn1Click(Sender: TObject);
var
I: IMyHello;
begin
I := GetIMyHello;
if Trim(edt1.Text) <> '' then begin
lbl2.Caption := I.Welcome(edt1.Text);
I := nil;
end
else begin
Application.MessageBox('請輸入姓名!', '系統信息', 0);
Exit;
end;
end;
procedure TForm1.btn2Click(Sender: TObject);
begin
Close;
end;
end.
在Delphi IDE環境,單擊“F9”運行客戶端程序,將彈出圖13-121所示對話框。
13.13.3 Web Services腳本
完成Web Services服務端和客戶端兩個小程序的編寫、編譯、執行后,您需要確保服務端程序是開啟的,關閉已運行的客戶端小程序。
接下來,您啟動LoadRunner 11.0,選擇“Web Services”協議,如圖13-122所示。
圖13-121 “樣例演示-客戶端”對話框 圖13-122 “New Virtual User”對話框
單擊【Create】按鈕,創建“Web Services”協議,在LoadRunner 腳本編輯環境單擊錄制紅色按鈕,在彈出的“Recording Wizard”對話框中單擊【Import】按鈕,在彈出的“Import Service”對話框中選擇“URL”選項,在文本框中輸入“http://localhost:5678/wsdl/IMyHello”,單擊【Import】按鈕,如圖13-123所示。
圖13-123 “Recording Wizard-Add Services頁”對話框
稍等片刻,將出現圖13-124所示界面信息,單擊【下一步(N)>】按鈕。
圖13-124 “Recording Wizard”對話框
在圖13-125所示對話框中輸入客戶端路徑相關信息“C:\mytest\client\Client.exe”,工作目錄為“C:\mytest\client”,(如果您的應用是基於B/S的,則選擇“Record default web browser”選項並輸入相應URL)單擊【完成】按鈕。
將彈出客戶端程序,在客戶端程序的文本輸入框,輸入“於涌”,單擊【調用接口】按鈕,此時將會在輸入框下方出現“歡迎於涌同學!”字符串,如圖13-126所示。
圖13-125 “Recording Wizard-Specify Application頁”對話框 圖13-126 “樣例演示-客戶端”對話框
此時將會產生如下代碼:
Action()
{
web_add_header("Content-Type", "text/xml");
web_add_header("SOAPAction", "\"urn:MyHelloIntf-IMyHello#Welcome\"");
web_add_header("User-Agent", "Borland SOAP 1.2");
soap_request("StepName=Welcome",
"URL=http://localhost:5678/soap/IMyHello",
"SOAPEnvelope=<?xml version=\"1.0\" encoding=\"GBK\" standalone=\"no\"?"
"><SOAP-ENV:Envelope xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/"
"encoding/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:SOAP-ENV=\"http:/"
"/schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Body SOAP-ENV"
":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><NS1"
":Welcome xmlns:NS1=\"urn:MyHelloIntf-IMyHello\"><name xsi:type=\"xsd"
":string\">於涌</name></NS1:Welcome></SOAP-ENV:Body></SOAP-ENV:Envelope>",
"Snapshot=t1.inf",
"ResponseParam=response",
LAST);
return 0;
}
我們最關心的內容應該是Web Services服務接口返回的內容,所以需要對腳本進行完善,腳本信息如下,黑色字體為新添加內容。
Action()
{
web_add_header("Content-Type", "text/xml");
web_add_header("SOAPAction", "\"urn:MyHelloIntf-IMyHello#Welcome\"");
web_add_header("User-Agent", "Borland SOAP 1.2");
soap_request("StepName=Welcome",
"URL=http://localhost:5678/soap/IMyHello",
"SOAPEnvelope=<?xml version=\"1.0\" encoding=\"GBK\" standalone=\"no\"?"
"><SOAP-ENV:Envelope xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/"
"encoding/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:SOAP-ENV=\"http:/"
"/schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Body SOAP-ENV"
":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><NS1"
":Welcome xmlns:NS1=\"urn:MyHelloIntf-IMyHello\"><name xsi:type=\"xsd"
":string\">於涌</name></NS1:Welcome></SOAP-ENV:Body></SOAP-ENV:Envelope>",
"Snapshot=t1.inf",
"ResponseParam=response",
LAST);
lr_save_string(lr_eval_string("{response}"), "XML_Input_Param");
lr_xml_get_values("XML={XML_Input_Param}",
"ValueParam=OutputParam",
"Query=/*/*/*/return",
LAST );
lr_output_message(lr_eval_string("返回結果 = {OutputParam}"));
return 0;
}
腳本的執行信息如下:
Virtual User Script started at : 2012-11-11 14:56:30
Starting action vuser_init.
Ending action vuser_init.
Running Vuser...
Starting iteration 1.
Starting action Action.
Action.c(4): Warning -26593: The header being added may cause unpredictable results when
applied to all ensuing URLs. It is added anyway [MsgId: MWAR-26593]
Action.c(4): web_add_header("Content-Type") highest severity level was "warning" [MsgId: MMSG-26391]
Action.c(6): web_add_header("SOAPAction") was successful [MsgId: MMSG-26392]
Action.c(8): web_add_header("User-Agent") was successful [MsgId: MMSG-26392]
Action.c(10): SOAP request "Welcome" started
Action.c(10): SOAP request "Welcome" was successful
Action.c(26): "lr_xml_get_values" succeeded, 1 match processed
Action.c(31): 返回結果 = 歡迎於涌同學!
Ending action Action.
Ending iteration 1.
Ending Vuser...
Starting action vuser_end.
Ending action vuser_end.
Vuser Terminated.
也許有的讀者會說:“我想先看看服務端返回的信息,這可不可以呢?”。“當然沒問題”,您只需要在腳本中加入“lr_output_message("%s",lr_eval_string("{response}")); ”(lr_xml_get_values()函數在前面已經介紹過,其在進行該協議類型腳本關聯時非常重要,請讀者朋友務必掌握),執行腳本時就會打印出響應的相關數據信息,如圖13-127所示。
圖13-127 WebServices相關腳本及執行結果
為了讓大家對返回的內容看得更加清楚,這里我將其拷貝出來,放置到my.xml文件中,其內容如圖13-128所示。
圖13-128 服務返回的XML相關信息
從圖13-128您會看到有一串亂碼,憑直覺這應該是“歡迎於涌同學!”,那么直覺對不對呢?您可以在腳本中加入以下兩行代碼,如圖13-129所示。
圖13-129 轉碼及輸出函數
其輸出結果果真為“歡迎於涌同學!”。圖13-129 中使用“lr_convert_string_encoding()”的函數就是將UTF8編碼轉碼為系統語言編碼的函數,經過轉碼后信息顯示正確了。也許有的讀者會問:“系統返回的xml響應信息有些顯得十分混亂,有沒有什么方法直接能看出其層次關系呢?”您可以借助樹視圖,單擊“Tree”按鈕,將出現圖13-130所示界面信息,是不是一目了然了呢!這也方便了您應用lr_xml_get_values()函數時填寫“Query”部分內容。
圖13-130 WebServices響應結果樹視圖
【重要提示】
(1)從上面Web Services程序編寫和腳本應用中,相信大家對該協議的應用已經有了非常清晰的認識,我們給大家演示的是基於C/S的小程序,在實際工作中您測試的應用可能是基於B/S的,它們在實際應用上並沒有大的區別,所以請讀者朋友們舉一反三。
(2)也許您也會像我一樣,在機器上安裝有殺毒軟件,如果您應用本書此客戶端和服務器端小程序時,有可能您的殺毒軟件會對其產生干擾,如:將小程序自動刪除、運行小程序沒反應等情況,此時應暫時關閉殺毒軟件,確保小應用可以正常運行。