概述
// 超文本传输协议(HyperText Transfer Protocol)是互联网上应用最广泛的协议,主要是用于网页的浏览。
// HTTP采用了请求-应答模式,也就是俗称的客户端/服务器模型,简称C/S模型。
// 其中,客户端向服务器发送一个请求,请求一般包括请求行、请求头和请求体三个部分。
// 在请求头中包含请求头中包含请求方法、URL、协议版本以及请求修饰符,客户消息和内容的类似于MIME的消息结构。
// 服务器以一个状态作为响应,响应的内容包括消息协议的版本,成功或者错误编码加上包含服务器信息、实体元信息以及可能的实体内容。
// HTTP常用的请求方法有GET、POST、PUT、DELETE四个,对应着对网络资源的查、改、增、删四个操作。
// HTTP采用TCP通信,主要是保证传输数据的稳定性、完整性。
// HTTP文件上传,主要是向服务器发送POST请求,将数据按照服务器的接收格式传输到服务器上,服务器再根据接收格式接收数据,完成文件的上传操作。
// HTTP文件下载,主要是向服务器发送GET请求,服务器接收到相应的请求后,便会读取资源数据并返回,这就完成的文件下载操作。
// PS:HttpOpenRequest函数:
// 功能:创建一个HTTP请求句柄。
// 原型:HINTERNET HttpOpenRequest(
//
_In_ HINTERNET hConnect,
//
_In_ LPCTSTR lpszVerb,
//
_In_ LPCTSTR lpszObjectName,
//
_In_ LPCTSTR lpszVersion,
//
_In_ LPCTSTR lpszReferer,
//
_In_ LPCTSTR *lplpszAcceptTypes,
//
_In_ DWORD dwFlags,
//
_In_ DWORD_PTR dwContext
//
)
// 参数:hConnect:由InternetConnect函数返回的连接句柄。
//
lpszVerb:请求的方法,默认为GET。
//
lpszObjectName:目标对象字符串,通常为文件名称、可自行模块或者查找标识符。
//
lpszVersion:HTTP版本,如果为NULL,表示使用1.1或1.0版本的HTTP协议。
//
lpszReferer:指向URL文档地址,如果为NULL,则不指定HTTP头。
//
lplpszAcceptTypes:表示客户接受的内容类型,比如"text/json"等。
//
dwFlags:标志,可以为以下值的一个或多个:
//
INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP:禁用检测这种特殊类型的重定向。
//
INTERNET_FLAG_IGNORE_CERT_CN_INVALID:根据请求中给出的主机名禁用检测从服务器返回的基于SSL/PCT的证书。
//
INTERNET_FLAG_KEEP_CONNECTION:保持连接。
//
INTERNET_FLAG_NO_AUTH:不会自动尝试验证。
//
INTERNET_FLAG_NO_COOKIES:不会自动为请求添加Cookie标头,也不会自动将返回的Cookie添加到Cookie数据库。
//
INTERNET_FLAG_NO_UI:禁用Cookie对话框。
//
INTERNET_FLAG_RELOAD:强制从源服务器上下载所请求的文件,而不是从缓存中下载。
//
INTERNET_FLAG_SECURE:启用HTTPS。
//
dwContext:指定OpenRequest操作的上下文标识。
// 结果:成功返回HTTP请求句柄,失败返回NULL。
// PS:HttpSendRequestEx函数:
// 功能:将指定的请求发送到HTTP服务器。
// 原型:BOOL HttpSendRequestEx(
//
_In_ HINTERNET hRequest,
//
_In_ LPINTERNET_BUFFERS lpBuffersIn,
//
_Out_ LPINTERNET_BUFFERS lpBuffersOut,
//
_In_ DWORD dwFlags,
//
_In_ DWORD_PTR dwContext
//
)
// 参数:hRequest:由HttpOpenRequest创建的请求句柄。
//
lpBuufersIn:可选,指向INTERNET_BUFFERS结构的指针。
//
lpBuffersOut:保留,必须为NULL。
//
dwFlags:保留,必须为NULL。
//
dwContext:指定由应用程序定义的上下文值,前提是状态回调函数已注册。
// 结果:成功返回TRUE,失败返回FALSE。
// PS:HttpQueryInfo函数:
// 功能:查询有关HTTP请求的信息。
// 原型:BOOL WINAPI HttpQueryInfo(
//
HINTERNET hRequest,
//
DWORD dwInfoLevel,
//
LPVOID lpBuffer,
//
LPDWORD lpdwBufferLength,
//
LPDWORD lpdwIndex
//
)
// 参数:hRequest:由HttpOpenRequest函数创建的Request句柄。
//
dwInfoLevel:请求要查询的属性和修改请求的标志组合。
//
lpBuffer:接收信息的缓存区。
//
lpdwBufferLength:接收缓存区大小。
//
lpdwIndex:用于枚举具有相同名称的多个头的基于零的头索引。
// 结果:成功,返回TURE,失败,返回FALSE。
// PS:基于WinInet库实现的HTTP文件上传步骤如下:
//
1.调用InternetCrackUrl函数对Url进行分解,从URL中提取网站的域名、资源路径、用户名、密码以及URL的附加信息等。
//
2.调用InternetOpen函数建立会话,获取会话句柄。连接过程中要指明INTERNET_SERVICE_HTTP,这表明连接到HTTP服务器上。
//
3.调用InternetConnect函数建立连接,获取连接句柄。
//
4.调用HttpOpenRequest打开HTTP的POST请求,同时指明POST的资源路径,并且设置HTTP的访问标志。
//
5.调用HttpSendRequestEx函数向服务器发送访问请求。
//
6.调用InternetWriteFile函数将本地数据写到远程主机上,即向服务器上传数据。等数据上传完毕后,调用HttpEndRequest函数来结束请求。
//
7.关闭句柄,释放缓存区资源。
// PS:示例代码:
// 数据上传
BOOL Http_Upload(char *pszUploadUrl, BYTE *pUploadData, DWORD dwUploadDataSize)
{
// 变量(略)
// 分解URL
if (FALSE == Http_UrlCrack(pszUploadUrl, szScheme, szHostName, szUserName, szPassword, szUrlPath, szExtraInfo, MAX_PATH))
{
return FALSE;
}
// 数据上传
do
{
// 建立会话
hInternet = ::InternetOpen("WinInet Http Upload v1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (NULL == hInternet)
{
Http_ShowError("InternetOpen");
break;
}
// 建立连接
hConnect = ::InternetConnect(hInternet, szHostName, INTERNET_DEFAULT_HTTP_PORT, szUserName, szPassword, INTERNET_SERVICE_HTTP, 0, 0);
if (NULL == hConnect)
{
Http_ShowError("InternetConnect");
break;
}
// 拼接szUrlPath
if (0 < ::lstrlen(szExtraInfo))
{
::lstrcat(szUrlPath, szExtraInfo);
}
// 设置标记
dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_COOKIES |
INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD;
// 创建POST请求
hRequest = ::HttpOpenRequest(hConnect, "POST", szUrlPath, NULL, NULL, NULL, dwOpenRequestFlags, 0);
if (NULL == hRequest)
{
Http_ShowError("HttpOpenRequest");
break;
}
// 发送请求,告诉服务器传输数据的总大小
::RtlZeroMemory(&internetBuffers, sizeof(internetBuffers));
internetBuffers.dwStructSize = sizeof(internetBuffers);
internetBuffers.dwBufferTotal = dwPostDataSize;
bRet = ::HttpSendRequestEx(hRequest, internetBuffers, NULL, 0, 0);
if (FALSE == bRet)
{
break;
}
// 发送数据
bRet = ::InternetWriteFile(hRequest, pUploadData, dwUploadDataSize, &dwRet);
if (FALSE == bRet)
{
break;
}
// 发送完毕,结束请求
bRet = ::HttpEndRequest(hRequest, NULL, 0, 0);
if (FALSE == bRet)
{
break;
}
// 接收响应报文信息头
pResponseHeaderInfo = new unsigned char[dwResponseHeaderInfoSize];
if (NULL == pResponseHeaderInfo)
{
break;
}
::RtlZeroMemory(pResponseHeaderInfo, dwResponseHeaderInfoSize);
bRet = ::HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, pResponseHeaderInfo, &dwResponseHeaderInfoSize, NULL);
if (FALSE == bRet)
{
Http_ShowError("HttpQueryInfo");
break;
}
// 从字段"Content-Length"中获取数据长度
bRet = Http_GetContentLength((char*)pResponseHeaderInfo, &dwResponseHeaderInfoSize);
if (FALSE == bRet)
{
break;
}
// 接收报文主体内容
pBuf = new BYTE[dwBufSize];
if (NULL = pBuf)
{
break;
}
pResponseBodyData = new BYTE[dwResponseBodyDataSize];
if (NULL == pResponseBodyData)
{
break;
}
::RtlZeroMemory(pResponseBodyData, dwResponseBodyDataSize);
do
{
::RtlZeroMemory(pBuf, dwBufSize);
bRet = ::InternetReadFile(hRequest, pBuf, dwBufSize, &dwRet);
if (FALSE == bRet)
{
Http_ShowError("InternetReadFile");
break;
}
::RtlCopyMemory((pResponseBodyData + dwOffset), pBuf, dwRet);
dwOffset += dwRet;
} while (dwResponseBodyDataSize > dwOffset);
} while (FALSE);
// 关闭并释放(略)
return bRet;
}
// PS:基于WinInet库的HTTP文件下载步骤:
//
1.调用InternetCrackUrl函数分解URL,从URL中提取网站的域名、资源路径以及URL的附加信息等。
//
2.调用InternetOpen函数建立会话并获取会话句柄。
//
3.调用InternetConnect函数建立连接,并指定连接的类型为INTERNET_SERVICE_HTTP,即连接到HTTP服务器上。
//
4.使用HttpOpenRequest创建一个GET请求,同时指明访问服务器的资源路径并设置HTTP的访问标志。
//
5.使用HttpSendRequestEx函数将访问请求发送到服务器上。这样服务器就可以获取请求信息和返回响应头信息。
//
6.调用HttpQueryInfo函数获取返回的Response Header信息,并根据Content-Length字段中的数据确定接收的数据长度,申请接收数据的缓存区。
//
7.循环调用InternetReadFile函数接收数据,直到接收数据的长度等于返回数据的长度。
//
8.关闭句柄,释放数据缓存区。
// PS:示例代码:
// 数据下载
BOOL Http_Download(char* pszDownloadUrl, BYTE **ppDownloadData, DWORD *pdwDownloadDataSize)
{
// 变量(略)
// 分解URL
if (FALSE == Http_UrlCrack(pszDownloadUrl, szScheme, szHostName, szUserName, szPassword, szUrlPath, szExtraInfo, MAX_PATH))
{
return FALSE;
}
// 拼接szUrlPath
if (0 < ::lstrlen(szExtraInfo))
{
::lstrcat(szUrlPath, szExtraInfo);
}
// 数据下载
do
{
// 建立会话
hInternet = ::InternetOpen("WinInte Http Download v1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (NULL == hInternet)
{
Http_ShowError("InternetOpen");
break;
}
// 建立连接
hConnect = ::InternetConnect(hInternet, szHostName, INTERNET_DEFAULT_HTTP_PORT, szUserName, szPassword, INTERNET_SERVICE_HTTP, 0, 0);
if (NULL == hConnect)
{
Http_ShowError("InternetConnect");
break;
}
// 设置标志
dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_COOKIES |
INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD;
// 创建请求
hRequest = ::HttpOpenRequest(hConnect, "GET", szUrlPath, NULL, NULL, NULL, dwOpenRequestFlags, 0);
if (NULL == hRequest)
{
Http_ShowError("HttpOpenRequest");
break;
}
// 发送请求
bRet = ::HttpSendRequestEx(hRequest, NULL, 0, NULL, 0);
if (FALSE == bRet)
{
Http_ShowError("HttpSendRequestEx");
break;
}
// 接收响应的报文信息头
pResponseHeaderInfo = new unsigned char[dwResponseHeaderInfoSize];
if (NULL == pResponseHeaderInfo)
{
break;
}
::RtlZeroMemory(pResponseHeaderInfo, dwResponseHeaderInfoSize);
// 查询响应信息头
bRet = ::HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, pResponseHeaderInfo, &dwResponseHeaderInfoSize);
if (FALSE == bRet)
{
Http_ShowError("HttpQueryInfo");
break;
}
// 从字段"Content-Length"中获取数据长度
bRet = Http_GetContentLength((char*)pResponseHeaderInfo, dwResponseHeaderInfoSize);
if (FALSE == bRet)
{
break;
}
// 申请动态内存,用于接收报文主体数据
pBuf = new BYTE[dwBufSize];
if (NULL == pBuf)
{
break;
}
::RtlZeroMemory(pDownloadData, dwDownloadDataSize);
// 循环接收数据
do
{
::RtlZeroMemory(pBuf, dwBufSize);
bRet = ::InternetReadFile(hRequest, pBuf, dwBufSize, &dwRet);
if (FALSE == bRet)
{
break;
}
::RtlCopyMemory((PVOID)(pDownloadData + dwOffset), pBuf, dwRet);
dwOffset += dwRet;
} while (dwDownloadDataSize > dwOffset);
// 返回数据
**ppDownloadData = pDownloadData;
*pdwDownloadDataSize = dwDownloadDataSize;
} while (FALSE);
// 关闭句柄,释放缓存区(略)
return bRet;
}
最后
以上就是眯眯眼便当为你收集整理的WinInet库之Http通信的全部内容,希望文章能够帮你解决WinInet库之Http通信所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复