强大的IWEB接口

    技术2022-05-11  12

    强大的IWEB接口     

    概述

    本文着重介绍了在1.1SDK中引入的IWEB接口,以及相关的IWebResp、IWebOpt、IwebUtil等API的使用方法。也包括各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和服务端URL“www.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”方式。

    取值:GET、POST。

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

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

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

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

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

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

    WEBREQUEST_NOKEEPALIVE:IWeb不会刻意地保持连接。在数据交换结束后立即释放连接。默认情况下,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_HEADERHANDLER和WEBOPT_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帮助文档。

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

    发起HTTP的POST请求

    HTTP的POST请求是指:把数据上传到服务器。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.x和2.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?param1=x%0”。

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

    保持连接和连接缓存

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

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

        


    最新回复(0)