原文:http://blog.csdn.net/zeng622peng/article/details/5969059
Post资料:
SUMMARY
To properly simulate a Form submission using WinInet, you need to send a header that indicates the proper Content-Type. For Forms, the proper Content-Type header is: Content-Type: application/x-www-form-urlencoded
MORE INFORMATION
In many cases, the server does not respond appropriately if a Content-Type is not specified. For example, the Active Server Pages component of IIS 3.0 actually checks this header specifically for 'application/x-www-form- urlencoded' before adding form variables to the "Request.Form" object. This MIME/Content-Type indicates that the data of the request is a list of URL- encoded form variables. URL-encoding means that space character (ASCII 32) is encoded as ' ', special character such '!' encoded in hexadecemal form as '!'.
Here is a snippet of code that uses the MFC WinInet classes to simulate a Form POST request:
CString strHeaders = _T("Content-Type: application/x-www-form-urlencoded");
// URL-encoded form variables -
// name = "John Doe", userid = "hithere", other = "P&Q"
CString strFormData = _T("name=John Doe&userid=hithere&other=P&Q");
CInternetSession session;
CHttpConnection* pConnection = session.GetHttpConnection(_T("ServerNameHere"));
CHttpFile* pFile = pConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST,_T("FormActionHere"));
BOOL result = pFile->SendRequest(strHeaders,(LPVOID)(LPCTSTR)strFormData, strFormData.GetLength());
Without MFC, the same code translates to straight SDK calls as follows:
static
TCHAR hdrs[] = _T("Content-Type: application/x-www-form-urlencoded");
static
TCHAR frmdata[] = _T("name=John Doe&userid=hithere&other=P&Q");
statuc TCHAR accept[] = _T("Accept: */*");
// for clarity, error-checking has been removed
HINTERNET hSession = InternetOpen("MyAgent",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hSession, _T("ServerNameHere"),
INTERNET_DEFAULT_HTTP_PORT,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
0,
1);
HINTERNET hRequest = HttpOpenRequest(hConnect,
"POST",
_T("FormActionHere"),
NULL,
NULL,
accept,
0,
1);
HttpSendRequest(hRequest,
hdrs,
strlen(hdrs),
frmdata,
strlen(frmdata));
// close any valid internet-handles
我这里有一段程序,用来在一个对话框里显示出一次http request的原始信息,不过使用Inet API做的,希望能有帮助。
void CHTTPRequestDlg::OnButtonRequest()
{
UpdateData(TRUE);
HINTERNET hInternet = InternetOpen("Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.0)",
INTERNET_OPEN_TYPE_DIRECT,
NULL,
NULL,
NULL);
HINTERNET hSession = InternetConnect(hInternet,
m_strHost,
m_nPort,
"username",
"password",
INTERNET_SERVICE_HTTP,
0,
0);
char* szAccept[] = {"*/*",NULL};
CString strVerb;
m_comboVerb.GetWindowText(strVerb);
HINTERNET hRequest = HttpOpenRequest(hSession,
strVerb,
m_strObject,
NULL,
NULL,
(LPCSTR*)szAccept,
0,
0);
struct
{
char* Language;
char* Encoding;
char* ContentType;
}Headers = {"Accept-Language:zh-cn/r/n",
"Accept-Encoding:gzip,deflate/r/n",
"Content-Type:application/x-www-form-urlencoded/r/n"};
if(m_bLanguage)
{
HttpAddRequestHeaders(hRequest,
Headers.Language,
-1,
HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
}
if(m_bEncoding)
{
HttpAddRequestHeaders(hRequest,
Headers.Encoding,
-1,
HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
}
if(m_bContentType)
{
HttpAddRequestHeaders(hRequest,
Headers.ContentType,
-1,
HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
}
LPCSTR lpAddHeader = NULL;
LPCSTR lpContent = NULL;
if(m_strHeaders.GetLength())
{
if(m_strHeaders.Right(2) != "/r/n")
{
m_strHeaders+="/r/n";
}
lpAddHeader = (LPCSTR)m_strHeaders;
}
if(m_strContent.GetLength() && (strVerb == "POST" || strVerb == "PUT"))
{
lpContent = (LPCSTR)m_strContent;
}
HttpSendRequest(hRequest,
lpAddHeader,
-1,
(LPVOID)lpContent,
m_strContent.GetLength());
m_editContentGot.SetSel(0,-1);
m_editContentGot.ReplaceSel("");
LPSTR lpszData; //buffer for the data
DWORD dwSize; //size of the data available
DWORD dwDownloaded; //size of the downloaded data
//Set the cursor to an hourglass.
SetCursor(LoadCursor(NULL,IDC_WAIT));
// This loop handles reading the data.
while(1)
{
// The call to InternetQueryDataAvailable determines the amount of
// data available to download.
if (!InternetQueryDataAvailable(hRequest,&dwSize,0,0))
{
SetCursor(LoadCursor(NULL,IDC_ARROW));
break;
}
else
{
// Allocates a buffer of the size returned by InternetQueryDataAvailable
lpszData = new char[dwSize+1];
// Reads the data from the HINTERNET handle.
if(!InternetReadFile(hRequest,(LPVOID)lpszData,dwSize,&dwDownloaded))
{
delete[] lpszData;
break;
}
else
{
// Adds a null terminator to the end of the data buffer
lpszData[dwDownloaded]='/0';
int nLen = m_editContentGot.GetWindowTextLength();
m_editContentGot.SetSel(nLen-1, nLen-1);
m_editContentGot.ReplaceSel(lpszData);
// Delete the two buffers
delete[] lpszData;
// Check the size of the remaining data. If it is zero, break.
if (dwDownloaded == 0)
{
break;
}
}
}
}
// Close the HINTERNET handle
InternetCloseHandle(hRequest);
InternetCloseHandle(hSession);
InternetCloseHandle(hInternet);
// Set the cursor back to an arrow
SetCursor(LoadCursor(NULL,IDC_ARROW));
}
==========================================
关文件:#include <afxinet.h>
使用MFC示例如下:
首先设置m_strRequest请求字符串 eg."name=aaa&pass=bbb";
m_strServerName 服务器名称或者IP eg."www.yahoo.com"
m_strObjectName 请求文件位置 eg. "pub/aaa.asp"
请求的结果存放在m_strHtml中
void func()
{
CInternetSession m_InetSession("session");
CHttpConnection *pServer = NULL;
CHttpFile* pFile = NULL;
try
{
INTERNET_PORT nPort;
nPort=80;
pServer = m_InetSession.GetHttpConnection(m_strServerName, nPort);
pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_POST,m_strObjectName);
char szHeaders[100];
strcpy(szHeaders,"Accept: text*/*/r/nContent-Type: application/x-www-form-urlencoded");
pFile->AddRequestHeaders(szHeaders);
pFile->SendRequestEx(m_strRequest.GetLength());
pFile->WriteString(m_strRequest);//重要-->m_Request 中有"name=aaa&name2=BBB&"
pFile->EndRequest();
DWORD dwRet;
pFile->QueryInfoStatusCode(dwRet);
CString str;
//m_Mutex.Lock();
m_strHtml="";
char szBuff[1024];
if (dwRet == HTTP_STATUS_OK)
{
UINT nRead;
while ((nRead = pFile->Read(szBuff,1023))>0)
{
m_strHtml += CString(szBuff,nRead);
}
}
//m_Mutex.Unlock();
delete pFile;
delete pServer;
}
catch (CInternetException* e)
{
CString s;
s.Format("Internet Exception/r/nm_dwError%u,m_dwContextError%u",e->m_dwError,e->m_dwContext);
AfxMessageBox(s);
//catch errors from WinInet
}
}
============================
1、获得WebBrowser Control的DWebBrowserEvents2::DocumentComplete事件
2、在DWebBrowserEvents2::DocumentComplete事件中根据IWebBrowser2::Document获得IHTMLDocument2
3、IHTMLDocument2::forms得到IHTMLElementCollection
4、在IHTMLElementCollection中根据name、tagName、ID得到指定的IHTMLElement
5、从IHTMLElement得到IHTMLFormElement
6、执行IHTMLFormElement::submit
==================================================
要正确模拟表单提交使用 WinInet, 您需要发送一个指示正确 Content-Type 标头。 对于窗体, 正确 Content-Type 标题是:
Content-Type: application/x-www-form-urlencoded
如果没有指定 Content-Type 在许多情况下, 服务器不响应正确。 在之前将表单变量添加到 " Request.Form "
对象例如, IIS 3.0 的 ActiveServerPages 组件实际上检查专门用于应用表单 ' www 程序 / x -
urlencoded ' 此标题。 此 MIME / 内容类型指示请求数据是 - URL 编码窗体变量的列表。 URL 编码意味着空格字符
(ASCII 32) 被编码为 + ' ', 特殊字符如 ' ! ' 以十六进制形式编码为 21 % '。
下面是使用 MFCWinInet 类来模拟 FormPOST 请求的代码段:
CString strHeaders =
_T("Content-Type: application/x-www-form-urlencoded");
// URL-encoded form variables -
// name = "John Doe", userid = "hithere", other = "P&Q"
CString strFormData = _T("name=John+Doe&userid=hithere&other=P%26Q");
CInternetSession session;
CHttpConnection* pConnection =
session.GetHttpConnection(_T("ServerNameHere"));
CHttpFile* pFile =
pConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST,
_T("FormActionHere"));
BOOL result = pFile->SendRequest(strHeaders,
(LPVOID)(LPCTSTR)strFormData, strFormData.GetLength());
没有 MFC, 相同的代码将转换为直 SDK 调用如下:
static TCHAR hdrs[] =
_T("Content-Type: application/x-www-form-urlencoded");
static TCHAR frmdata[] =
_T("name=John+Doe&userid=hithere&other=P%26Q");
static LPSTR accept[2]={"*/*", NULL};
// for clarity, error-checking has been removed
HINTERNET hSession = InternetOpen("MyAgent",
INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hSession, _T("ServerNameHere"),
INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = HttpOpenRequest(hConnect, "POST",
_T("FormActionHere"), NULL, NULL, accept, 0, 1);
HttpSendRequest(hRequest, hdrs, strlen(hdrs), frmdata, strlen(frmdata));
// close any valid internet-handles
===================================================
Get资料:
#include "winsock2.h"
#include "stdio.h"
#include "Wininet.h"
#pragma comment (lib,"Wininet.lib")
void main()
{
HINTERNET hNet = ::InternetOpen("Google page", //当HTTP协议使用时,这个参数随意赋值
PRE_CONFIG_INTERNET_ACCESS, //访问类型指示Win32网络函数使用登记信息去发现一个服务器。
NULL,
INTERNET_INVALID_PORT_NUMBER, //使用INTERNET_INVALID_PORT_NUMBER相当于提供却省的端口数。
0 //标志去指示使用返回句句柄的将来的Internet函数将"不"为回调函数发送状态信息
) ;
HINTERNET hUrlFile = ::InternetOpenUrl(hNet, //从InternetOpen返回的句柄
"http://www.google.com", //需要打开的URL
NULL, //用来向服务器传送额外的信息,一般为NULL
0, //用来向服务器传送额外的信息,一般为 0
INTERNET_FLAG_RELOAD, //InternetOpenUrl行为的标志
0) ; //信息将不会被送到状态回调函数
char buffer[1024] ;
DWORD dwBytesRead = 0;
BOOL bRead = ::InternetReadFile(hUrlFile, //InternetOpenUrl返回的句柄
buffer, //保留数据的缓冲区
sizeof(buffer),
&dwBytesRead); //指向包含读入缓冲区字节数的变量的指针;
//如果返回值是TRUE,而且这里指向0,则文件已经读到了文件的末尾。
::InternetCloseHandle(hUrlFile) ;
::InternetCloseHandle(hNet) ;
printf("%s", buffer);
}