强大的IWEB接口

阅读更多

概述

本文着重介绍了在1.1SDK中引入的IWEB接口,以及相关的IWebRespIWebOptIwebUtilAPI的使用方法。也包括各API的功能和与其他API(例如IHTMLVIEWER)的交互。

―――――――――――――――――――――――――――――――――――――――

基本作用

BREW应用中,IWEB接口主要用于发起HTTP请求。在HTTP请求中,既可以通过“GET”方式获取文件,也可以通过“POST”方式上传数据,这两种方式IWEB都支持。IWEB管理自身的连接和套接字,因此更利于网络传输。

IWEB_GetPesponse函数用于开始网络传输。

Void IWEB_GetResponse(

Iweb * pIWeb,

IwebResp ** ppiwresp,

AEECallBack * pcb,

Const char * cpszUrl,

...

 )

其中:

pIWeb 指向一个已实例化的IWeb对象的有效指针。

ppiwresp 指向IwebResp指针的有效指针。

pcb 指向一个已实例化的AEECallBack对象的有效指针。

cpszUrl 指向URL的指针。

... 是WebOpt中各项的名称和取值,成对排列,以WEBOPT_END结束。

注意:IwebResp指针不可以创建在在栈里。为了保证它在整个回调的过程中一直有效,创建在应用对应的结构体里比较好。

URL不可以包含任何保留字符。如果必须包含,请注意转换。详见本文 “在URL中使用保留字符”部分。

IWeb请求一个文件,最简单的形式如下:

//Create IWeb instance

ISHELL_CreateInstance(pMe->a.m_pIShell,AEECLSID_WEB,(viod**)&pMe->m_pIWeb);

//Initialize the callback to WebReadCB

CALLBACK_Init(&pMe->m_Callback,WebReadCB,pMe);

//Request IWEB to fetch the URL

IWEB_CetResponse(pMe->m_pIWeb,(pMe->m_pIWeb,&pMe->m_pIWebResp,&pMe->m_Callback,http://www.qualcomm.com,WEBOPT_END));

注意此函数中参数传递的特殊语法。

IWEB和服务端URLwww.qualcomm.com”建立一个网络连接,并请求得到文件。当IWEB引擎获得了来自服务端的响应,它会通过pcb传递给AEECallBack中的回调函数。如果请求文件的方式没有指定,默认为“GET”。请求文件的方式以及其他选项的设置方法,参见本文的“IWEB_GetResponse请求中WebOpts的设置”。

WebRespInfo结构体中包含了响应的消息体和其他相关信息(比如错误号、长度、类型等),所以,可以通过IWEB_GetInfo函数解析WebRespInfo取得响应的内容。具体参见本文的“如何理解WebRespInfo中的错误号”部分。

//Callback

static void WebReadCB(void * cxt)

{

...

//get information about the response

WebRespInfo * pWebRespInfo = IWEBRESP_GetInfo(pMe->m_pWebResp);

//the body of the response is contained in the ISOURCE

ISource * pISource = pWebRespInfo->pisMesssage

}

―――――――――――――――――――――――――――――――――――――――

IWEB_GetResponse请求中WebOpts的设置

前面,我们已经了解用IWEB开始一个简单的HTTP传输的方法,现在通过学习WebOpts的使用,将我们对IWEB接口的了解深入一步。

一个WebOpt包含两项内容:选项名称及其取值。这些WebOpt应该被加入到IWeb_GetResponse函数中,用于配置将要发出的请求。WebOpt可以以两种方式添加:

使用IWEB_AddOpt

以这种方式添加的选项是永久的——只要IWeb对象没有释放,这个设置一直有效。

int i = 0;

WebOpt awo[10];

//Add handler data

awo[i].nId = WEBOPT_HANDLERDATA;

awo[i].nVal = (void*)pMe;

i++;

//add the handler function for status callbacks

awo[i].nId = WEBOPT_STATUSHANDLER;

awo[i].nVal = (void*)WebStatusNotification;

i++;

//add the option stating which method

awo[i].nId = WEBOPT_METHOD;

awo[i].nVal = (void*)”GET”;

i++;

//marks the end of the arrary of WebOpts

Awo[i].nId = WEBOPT_END;

//add options

IWEB_AddOpt(pApp->m_pIWeb,awo);

IWeb_GetResponse(pMe->m_pIWeb,(pMe->m_pIWeb,&pMe->m_pIWebresp,&pMe->m_Callback,”thhp://webber.qualcomm.com”,WEBOPT_END));

直接添加

WebOpt的选项名和值可以在IWeb_GetResponse函数中直接设置:

IWeb_GetResponse(pMe->m_pIWeb,(pMe->m_pIWeb,&pMe->m_pIWebresp,&pMe->m_Callback,”http://webber.qualcomm.com”,

WEBOPT_HANDLERDATA,pMe

WEBOPT_STATUSHANDLER,WebStatusNotification,

WEBOPT_METHOD,”GET”,

WEBOPT_END));

这种方式添加的设置,只在这个IWeb_GetResponse中有效。

注意:不管以哪种方式添加,请求的设置应该在整个回调的过程中保持有效。若想设置被自动复制到需要的地方,在选项列中添加WEBOPT_COPYOPTS

有时候,AEEWeb.h文件中的解释比API帮助中的更加详细。常用的WebOptions和解释如下:

WEBOPT_METHOD:设定使用“GET”或者“POST”方式。

取值:GETPOST

WEBOPT_BODY:用于设置POST的消息体。

WEBOPT_CONNECTTIMEOUT:设置在尝试成功建立连接的过程中,IWeb需要等待的时间。时间到则放弃连接,并返回连接错误号。以毫秒计算,默认值为AEENet的连接时长。设为0表示使用系统默认值,-1表示无穷大。这个值要足够一次成功的连接。假设成功建立了连接,服务器响应却比较缓慢,在这个过程中,IWeb不可以报“连接超时”。可以根据需要使用IShell_SetTimer

WEBOPT_IDLECONNTIMEOUT:一个空闲连接保持的时间,此时间到,则关闭连接。默认值为InetMgrPPP的连接时间,设为-1表示无穷大。

WEB_HEADER:设置特殊的http消息头,由CRLF组成。CRLF是指单独列出的名称和取值,例如:”Name1:v1\r\nName2:v2\r\n”

WEBOPT_PROXYSPEC用于设置代理。详见《BREWWebProxySpecKnowledgeBase》。

WEBOPT_FLAGS这个设置会影响底层协议引擎的行为。这些标志使我们在使用连接时取得更多的控制权。已实现的标志如下:

WEBREQUEST_NOKEEPALIVEIWeb不会刻意地保持连接。在数据交换结束后立即释放连接。默认情况下,IWeb尽力保持连接。

WEBREQUEST_FORCENEWCONN:在已经和某服务器已经建立连接后,每次连接这个服务器,IWeb都会重新建立一个连接,而不沿用以前的连接。这样做,您将承担以下风险:手机上没有空闲套接字可用、传输失败。默认情况下,IWeb会重复利用已有的连接。

WEBREQUEST_NOWAITCONN:如果没有可用的连接,建立新连接。通常情况下,如果已有一个连接正在工作,IWeb会等待这个连接释放,然后建立新的。如果设置这个标志,IWeb会立刻建立新连接。

其他选项的详细信息,参见AEEWeb.h

―――――――――――――――――――――――――――――――――――――――

如何理解WebRespInfo中的错误号?

发送请求给服务器,得到服务器的响应,我请求的结果在那里?上面提到过,回调中包含一个指向IwebResp对象的指针。可以通过如下方法从IwebResp中得到信息:

//callback

static viod WebReadCB(viod*cxt)

{

//get information about the response

WebRespInfo * pWebRespInfo = IWEBRESP_GetInfo(pMe->m_pIWebResp);

}

pWebRespInfo->nCode包含响应的状态:成功或者失败。正数1代表由服务器返回,负数代表系统错误,参见AEEError.h。为了理解nCode的意思,可以使用以下宏:

WEB_ERROR_SUCCESSED(nCode):这个宏在传输成功时返回TRUE

WEB_ERROR_MAP(nCode):如果是HTTP错误,返回WEB_ERROR_PROTOCOL系列错误号。错误号对应的意思参见AEEWeb.h或者RFC2626

检查响应的状态和消息头

如果有需要,查看来自服务器的响应的消息头是很容易实现的。在响应中设置WEBOPT_HEADERHANDLERWEBOPT_STATUSHANDLER即可。这些选项为相应的消息头和状态设置了回调函数。

用法:

IWEB_GetResponse(pApp->m_pIWeb,(pApp->m_pIWeb,&pwa->piWResp,&pwa->cb,pszUrl,

WEBOPT_HEADERHANDLER,WebAction_Header,

WEBOPT_STATUSHANDLER,WebAction_Status,

WEBOPT_END));

WebAction_Header属于PFNWEBHEADER类型,WebAction_Status属于PFNWEBSTATUS类型。更多信息参见API帮助文档。

―――――――――――――――――――――――――――――――――――――――

发起HTTPPOST请求

HTTPPOST请求是指:把数据上传到服务器。IWeb要先准备好上传的数据流。

// set up the callback

CALLBACK_Init(&pMe->m_Callback, WebReadCB, pMe);

// Create a Source Util object which will create an ISource object

// from a buffer, file, socket, etc.

ISHELL_CreateInstance(pMe->a.m_pIShell, AEECLSID_SOURCEUTIL, (void

**)&pMe->m_pISourceUtil);

// Create ISOURCE object

ret = ISOURCEUTIL_SourceFromMemory(pMe->m_pISourceUtil,

pMe->m_szData, // data in buffer

pMe->m_nContentLength, // length of data

NULL,// No callback

NULL,

&pMe->m_pISource //object to be created

);

// Kick off the transaction

IWEB_GetResponse(pMe->m_pIWeb,

(pMe->m_pIWeb,

&pMe->m_pIWebResp,

&pMe->m_Callback,

pMe->m_pURL,

WEBOPT_METHOD, "POST", // Set method to POST

WEBOPT_BODY, pMe->m_pISource, // Set body of message

// to ISOURCE object

WEBOPT_CONTENTLENGTH, pMe->m_dwContentLength,

WEBOPT_END));

跟“GET”请求类似,回调函数必须有正确的代码和数据才可以被调用。

注意:BREW1.x2.0中,如果POST的消息体很长会出问题。

―――――――――――――――――――――――――――――――――――――――

URL中使用保留字符

HTTP请求中,URL中不能含有保留字符。如果不可避免,在发出请求之前,URL得被译码成为可接受的格式——使用IWEB_UrlEncode

char * IWEBUTIL_UrlEncode

(

IWebUtil * pIWebUtil,

const char * cpcIn,

int * pnInLen,

char * pcOut,

int * pnOutLen

)

这个方法可以根据RFC2936译出一个包含URL的字符串。

注意:只对URL后缀中的保留字符重新译码,而不是整个URL

假设URL像这样:“http://www.qualcomm.com/test?param1=x”只译码“test?param1=x

”部分。用例如下:

// Determine what the length of the output buffer needs to be

IWEBUTIL_UrlEncode(pMe->m_pIWebUtil,

(const char *)(buf), // buffer containing the suffix

// of URL with reserved chars

&nDataLen, // number of characters to be

encoded

NULL, // if NULL, method calculates

//size of buffer needed

&pMe->m_dwContentLength // contains the length

// of the buffer required

);

// Allocate space to hold the encoded string

if(pMe->m_dwContentLength)

pMe->m_szData = (char*) MALLOC(pMe->m_dwContentLength);

// Encode the string.

IWEBUTIL_UrlEncode(pMe->m_pIWebUtil, (const char *)(buf), &nDataLen,

pMe->m_szData, &pMe->m_dwContentLength);

译码后的字符串类似于“test%3Fparam1%3Dx%0

m_szData包含译码后的URL后缀。需要和URL的前部分连接起来,才可以用于IWEB_GetResponse

保持连接和连接缓存

HTTP1.1引入了通过Keep-Alives使连接持久的概念。IWeb利用了这一特点,并作为默认设置。用WEBREQUEST_NOKEEPALIVE WEBOPT_FLAG可以取消。

如果应用请求服务器www.qualcomm.com/index.htmlIWeb建立一个到此地址的连接。请求得到响应后,IWeb并不关闭连接,而是加入缓存。如果又有需要连接到同一服务器的请求,例如www.qualcomm.com/developer.htmlIWeb会重用这个连接。这一功能可以通过WEBOPT_FLAGS关闭。

尽管如此,持久连接也是受限的。Keepalives取决于消息头中Content-Length的内容。在一个有效的“Content-Length:xxx”消息头中,只能包含“Connection:Keep-Alive”。如果想告知对方何时停止读数据流,就得传送内容长度(不送Connection:Keep-Alive),连接就断了。

由于很难或者说根本不可能提供一个“Content-Length:xxx”的有效消息头,大部分服务器在提供了CGI或其他动态内容后,回到“Connection:Close”。

就算有效的内容长度消息头存在,服务器也可以在任何时间关闭连接。这是HTTP标准的一部分。根本没有办法来确保一个持久的连接。

―――――――――――――――――――――――――――――――――――――――

巧用IWEBUTIL_ParseFormFields

当应用中需要收集用户的信息并把它传送到服务器时,这个方法特别好用。

BREW应用可以利用IHTMLViewer接口在手机上显示HTML表格。用户可以在这个表格里输入必要的信息。这些信息可能要被传送到服务器,也可能应用要利用这些信息实现用户要求的功能。

比如,一个文本框用于用户输入铃声的名字。这个信息也许会被传送到服务器去查找相应的铃声文件。在同一张表中,也许还有个音量的多选框,让用户选择铃声播放的音量。这个信息不必送到服务器,应用会根据它来改变自身相应的功能。

当用户点表单的提交按钮时,HVN_SUBMIT就会连同URL一起,被传送给HTMLViewer的回调函数。其中,URL的后缀包含表域及其内容。

name1=value1&name2=value2&name3=value3& ...

name1=value1;name2=value2;name3=value3; ....

IWEBUTIL_ParseFormFields可以从这个后缀中得到各表域和值,具体如下:

假设传递到回调函数的URL如下:

request:ringer?ringer=Sacrifice&volume=50

//find the suffix

pszIter = STRCHREND(pszIter, '?');

if (*pszIter)

++pszIter;

{

IWebUtil *piwu;

WebFormField wff[4]; // Create an array of WebFormField structs

ISHELL_CreateInstance(pApp->a.m_pIShell, AEECLSID_WEBUTIL,

(void **)&piwu)) ;

// This populates the WebFormField structs with a maximum of 4 fields

IWEBUTIL_ParseFormFields(piwu,&pszIter,wff,4,0);

IWEBUTIL_Release(piwu);

piwu = 0;

}

现在,表域的名称和值都包含在WebFormFields中了。

你可能感兴趣的:(BREW,应用服务器,网络应用,Web,网络协议)