Symbian中的Http开发详解

    技术2026-04-05  1

    1 打开一个会话

    Http客户端会话由声明一个RHttpSession对象并调用它的OpenL()方法开始。

    RHTTPSession iSession;

    iSession.OpenL();

    2 创建一个事务

    要创建一个新的事务,客户端必须指定URI、HTTP请求方法和一个用于接收事务处理期间的事件的callback对象,该回调对象必须继承自MHTTPTransactionCallBack接口。RHTTPTransaction句柄由唯一地定义新事物的会话返回。

    void CHttpClient::InvokeHttpMethodL(const TDesC8& aUri, RStringF aMethod)

    {

    ...

    TUriParser8 uri;

    uri.Parse(aUri);

    RHTTPTransaction trans = iSession.OpenTransactionL(uri, *iTransObs, aMethod);

    ...

    };

    OpenTransactionL()的第二个参数表示回调对象。

    3 设置请求头

    在打开了事务之后,如果有需要,客户端就要设置请求头。但是,对于简单事务来说,请求头的使用是可选的,因为HTTP/1.1的请求头会被自动生成。

    可以使用RHTTPHeaders类访问与事务请求或事务响应相关的头部。该句柄是从事务相关的RHTTPRequest或RHTTPResponse对象中取得的。

    RHTTPHeaders hdr = trans.Request().GetHeaderCollection();

    // Add headers appropriate to all methods

    SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);

    SetHeaderL(hdr, HTTP::EAccept, KAccept);

    ...

    void CHttpClient::SetHeaderL(RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8& aHdrValue)

    {

    RStringF valStr = iSession.StringPool().OpenFStringL(aHdrValue);

    THTTPHdrVal val(valStr);

    aHeaders.SetFieldL(iSession.StringPool().StringF(aHdrField), val);

    valStr.Close();

    }

    头部域类型是使用HTTP名字空间的枚举来指定,如:HTTP::EUserAgent。该类用于拥有头部域的值:THTTPHdrVal,就像一个C++联合类型,在其中它可以拥有不同的数据类型。

    4 启动事务

    设置了头部域后,一个不带请求体的简单事务就可以立即启动了。但这只是适用于诸如GET、HEAD和TRACE等HTTP方法的情况。而不适用于另外一些请求中包括主体的HTTP方法,如POST。客户端向其发送请求体数据的数据提供者必须在事务启动之前关联到事务上。

    当事务准备启动时,客户端调用RHTTPTransaction::SubmitL()表示请求应该被提交了。

    ...

    // submit the transaction

    trans.SubmitL();

    // Start the scheduler, once the transaction completes or is cancelled //on an error the scheduler will be stopped in the event handler

    CActiveScheduler::Start();

    5 接收事务事件

    当客户端从HTTP服务器收到数据,事件也会被生成并通过会话过滤器传回到客户端。事件到达客户端时,HTTP会唤醒事务回调对象,也即 MHFRunL (RHTTPTransaction aTransaction, const THTTPEvent &aEvent)方法。

    在该方法中可通过以下方式利用事务响应取得响应状态码和文本描述:

    case THTTPEvent::EGotResponseHeaders:

    {

    RHTTPResponse resp = aTransaction.Response();

    TInt status = resp.StatusCode();

    RStringF statusStr = resp.StatusText();

    下面的代码则是使用THTTPHdrFieldIter类循环取得头部域数据:

        RHTTPResponse resp = aTrans.Response();

        RStringPool strP = aTrans.Session().StringPool();

        RHTTPHeaders hdr = resp.GetHeaderCollection();

        THTTPHdrFieldIter it = hdr.Fields();

        TBuf<KMaxHeaderNameLen> fieldName16;

        TBuf<KMaxHeaderValueLen> fieldVal16;

        while (it.AtEnd() == EFalse)

        {

        // Get the name of the next header field

        RStringTokenF fieldName = it();

        RStringF fieldNameStr = strP.StringF(fieldName);

        // Check it does indeed exist

        THTTPHdrVal fieldVal;

        if (hdr.GetField(fieldNameStr,0,fieldVal) == KErrNone)

          {

           ...

           // Display realm for WWW-Authenticate header

           RStringF wwwAuth = strP.StringF(HTTP::EWWWAuthenticate, RHTTPSession::GetTable());

           if (fieldNameStr == wwwAuth)

             {

             // check the auth scheme is 'basic'

             RStringF basic = strP.StringF(HTTP::EBasic,RHTTPSession::GetTable());

             RStringF realm = strP.StringF(HTTP::ERealm, RHTTPSession::GetTable());

             THTTPHdrVal realmVal;

             if (fieldVal.StrF() == basic)

              // check the header has a 'realm' parameter

              if (hdr.GetParam(wwwAuth, realm, realmVal) == KErrNone)

               {

               RStringF realmValStr = strP.StringF(realmVal.StrF());

               fieldVal16.Copy(realmValStr);

               Printf(_L("Realm is: %S/n"), &fieldVal16);

               }

            }

         }

         // Advance the iterator

         ++it;

     }

    6 取得响应体

    要取得响应体,就必须使用包含在事务响应里的数据提供者。在客户端完成处理所有的响应体数据片后,必须数据释放数据提供者。

    case THTTPEvent::EGotResponseBodyData:

     {

     // Some (more) body data has been received. Get the body data supplier

     MHTTPDataSupplier* body = aTransaction.Response().Body();

     TPtrC8 dataChunk;

     TBool isLast = body->GetNextDataPart(dataChunk);

     Dump(dataChunk);

     if (isLast)

       Printf(_L("Got the last data chunk./n"));

    // Done with that bit of body data

     body->ReleaseData();

     }

     break;

    7 完成事务

    事务的完成(不管是成功还是失败),都要停止本地活动调度器。枚举值EResponseComplete仅是事务完成的一个信号,而不用于完成任何具体的工作。具体的工作放在成功或是失败的分支里处理:

    case THTTPEvent::EResponseComplete:

        {

        // The transaction's response is complete

        Printf(_L("/nTransaction Complete/n"));

        }

        break;

    case THTTPEvent::ESucceeded:

        {

        Printf(_L("Transaction Successful/n"));

        aTransaction.Close();

        CActiveScheduler::Stop();

        }

        break;

    case THTTPEvent::EFailed:

        {

        Printf(_L("Transaction Failed/n"));

        aTransaction.Close();

        CActiveScheduler::Stop();

        }

        break;

    最后要使用RHTTPTransaction::Close()关闭事务,这个调用将释放所有关联到事务的资源。

    8 终止会话

    客户端准备终止时,要关闭会话:

    CHttpClient::~CHttpClient()

        {

        iSession.Close();

        ...

        }

    关闭会话导致所有的资源被返回给系统,所有残存的未完成事务都将被立即取消。

    最新回复(0)