[轉]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
 

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