[转]POST和GET请求,302跳转

2010-08-17 18:33

 

连网建立成功后,就需要和服务器进行交互了。
首先讲一下POST和GET,PEST就是上传数据,GET就是下载数据。
这两者在编程方面的区别就是POST类型需要有主体。

 

 

首先需要设置URL,symbian提供了URL的类:TUriParser8
一般会把自己要用到的URL定义成一个TDesC8类型的变量,然后用TUriParser8解析TDesC8:
TUriParser8 uri;
uri.Parse( aUrl );


URL设置好了之后,建立一个事务:
RStringF method = RHTTPSession.StringPool().StringF( HTTP::EPOST,RHTTPSession::GetTable());
这里定义了请求的类型,这里是POST。


然后把这个事务和RHTTPSession关联起来:(做这些工作是在连网成功之后做的。所以RHTTPSession这些都已经OPEN了)
RHTTPTransaction = RHTTPSession.OpenTransactionL( uri, *this, method );


然后就需要设置请求头部分,请求头可以有很多参数。这里就设置了3个:
RHTTPHeaders headers = iHttpTransaction.Request().GetHeaderCollection();
AddHeaderL(headers, HTTP::EUserAgent, KUserAgent);//客户程序名称_LIT8( KUserAgent, "BS Upload" );
AddHeaderL(headers, HTTP::EAccept, KAccept);//允许服务器响应的数据的类型_LIT8( KAccept, "*/*" );
AddHeaderL(headers, HTTP::EContentType, KPostContentType);//POST主体的数据类型_LIT8(KPostContentType, "text/plain");


接着就要设置POST主体了:
if( iPostDateBuf8 )
{
delete iPostDateBuf8;
iPostDateBuf8 = NULL;
}
iPostDateBuf8 = HBufC8::NewL( aDody.Length() );
iPostDateBuf8->Des().Copy( aDody );
iPostDatePtr8.Set( iPostDateBuf8->Des() );
iPostDateLength = iPostDatePtr8.Length();
MHTTPDataSupplier* dataSupplier = this;
iHttpTransaction.Request().SetBody(*dataSupplier);
iContentLen = 0;
iHttpTransaction.SubmitL();


这里MHTTPDataSupplier是symbian提供的设置主体的一个类,HTTP的类需要继承MHTTPDataSupplier这个类,这里 定义了一个MHTTPDataSupplier的对象,由于这里的HTTP的类继承自MHTTPDataSupplier,就可以把this赋值给 MHTTPDataSupplier的对象了。


这里就会出现问题了,MHTTPDataSupplier这里没有和我定义的POST的主体iPostDateBuf8关联起来啊。
其实是这样的,MHTTPDataSupplier里边有4个纯虚函数,我的HTTP继承自MHTTPDataSupplier,必须实现里边的4个纯虚函数:
virtual TBool GetNextDataPart(TPtrC8& aDataPart);
virtual void ReleaseData();
virtual TInt OverallDataSize();
virtual TInt Reset();


这这4个函数里边实现设置POST的主体:
TBool CbsuploadHttpEngine::GetNextDataPart(TPtrC8& aDataPart)
{
TBool retVal = EFalse;
aDataPart.Set( iPostDatePtr8 );//aDataPart是POST的主体,aDataPart指向我需要上传的数据
retVal = ( iPostDatePtr8.Length() == 0 );
return retVal;
}


void CbsuploadHttpEngine::ReleaseData()
{
TPtr8 buff = iPostDateBuf8->Des();
buff.Zero();
}


TInt CbsuploadHttpEngine::OverallDataSize()
{
return iPostDateLength;
}


TInt CbsuploadHttpEngine::Reset()
{
return KErrNotSupported;
}


这个是这4个函数的实现方法,就实现了POST主体的设置了。
主体设置成功了,就把事务提交,HTTP就会与服务器交互了。
iHttpTransaction.SubmitL();//提交事务

 

 

GET和POST大体一样,就是没有主体部分了:
TUriParser8 uri;
uri.Parse( aUrl );
//新建一个事务transaction
RStringF method = iHttpSession.StringPool().StringF( HTTP::EGET,RHTTPSession::GetTable());
iHttpTransaction = iHttpSession.OpenTransactionL( uri, *this, method );
//设置header( 暂时先添加EUserAgent、EAccept,看浏览器中有还有别的)
RHTTPHeaders hdr = iHttpTransaction.Request().GetHeaderCollection();
AddHeaderL( hdr, HTTP::EUserAgent, KUserAgent );
AddHeaderL( hdr, HTTP::EAccept, KAccept );
//清除上次请求的参数
iContentLen = 0;
//提交请求
iHttpTransaction.SubmitL();

 

上传到服务器了,然后函数得有接受服务器响应的函数啊,这里HTTP继承自MHTTPTransactionCallback这个类,这个类里边就有2个接受服务器响应的函数:
virtual void MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent);
virtual TInt MHFRunError(TInt aError, RHTTPTransaction aTransaction, const THTTPEvent& aEvent);
MHFRunL函数是接受服务器正常的响应的MHFRunL函数异常退出了之后会触发MHFRunError函数。


参数aEvent表示了事件的类型。
常用的有:
THTTPEvent::EGotResponseHeaders在接收完响应头的时候触发
THTTPEvent::EGotResponseBodyData在接受完主体之后触发
THTTPEvent::EResponseComplete全部完成后触发
THTTPEvent::ESucceeded这个也是在完成之后触发,在THTTPEvent::EResponseComplete之后
THTTPEvent::EFailed返回的是错误码触发

THTTPEvent::EGotResponseHeaders触发后,使用symbian提供的处理响应的类RHTTPResponse进行处理:


RHTTPResponse resp = aTransaction.Response();
TInt statusCode = resp.StatusCode();
RStringF statusStr = resp.StatusText();
HBufC* statusBuf = HBufC::NewLC(statusStr.DesC().Length());
statusBuf->Des().Copy(statusStr.DesC());

THTTPEvent::EGotResponseBodyData触发后,使用MHTTPDataSupplier来接受主体部分:
MHTTPDataSupplier* dataSupplier = aTransaction.Response().Body();
TPtrC8 ptr;
dataSupplier->GetNextDataPart(ptr);
HBufC* buf = HBufC::NewLC(ptr.Length());
buf->Des().Copy(ptr);
if (!iResponseBuffer)
{
iResponseBuffer = buf->AllocL();
}
else
{
iResponseBuffer = iResponseBuffer->ReAllocL(iResponseBuffer->Length() + buf->Length());
iResponseBuffer->Des().Append(*buf);
}
CleanupStack::PopAndDestroy(buf);
dataSupplier->ReleaseData();

然后再在THTTPEvent::EResponseComplete和THTTPEvent::EFailed做相应的处理。

 


说下302跳转:
服务器那边有得时候需要手机完成一个302的跳转:
需要程序里边处理


302是在服务器响应回来的头里边有一个URL,然后返回一个错误码是302。
symbian里边在接受到响应头后在头里边找到这个URL,这个URL定义在Location里边:


RHTTPHeaders hdr = resp.GetHeaderCollection();
RStringF fieldStr = iHttpSession.StringPool().OpenFStringL( _L8("Location") );
CleanupClosePushL( fieldStr );
TBuf8<256> iFieldValue;
TPtrC8 rawField(iFieldValue);
iUrl302->Des().Zero();
if (hdr.GetRawField(fieldStr, rawField) != KErrNotFound)
{
TPtr8 pUrl = iUrl302->Des();
pUrl.Append( rawField );
}
CleanupStack::PopAndDestroy( &fieldStr );

 

然后再THTTPEvent::EFailed这个里边处理收到302后要做的事情:
Cancel();
RHTTPResponse resp = aTransaction.Response();
TInt status = resp.StatusCode();
iNetworkCode = status;
if( iNetworkCode==302 )
{
//需要做的处理
}
else
{
//需要做的处理
}

 

 

连接:http://blog.sina.com.cn/s/blog_4ca2ebd40100jve0.html

相关链接:

http://hi.baidu.com/addkaka/blog/item/4daaa267ff4bc42eab184ca5.html

http://www.360doc.com/content/09/1111/16/470973_8814280.shtml

http://blog.csdn.net/zhouyi445/archive/2009/12/17/5020006.aspx
 

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