模仿QT源码中的http/https访问网页 GET/POST封装

这段代码也是经历我的“千锤百炼”,用到了我学到的很多东西。比如智能指针等等
还望各位多多指教

#pragma once
#include <string>
#include <sstream>
#include <memory>
#include <vector>
#include <map>
#include <winhttp.h>


class NetworkReply;
using Header = std::multimap <std::string, std::string>;
using HString = std::string;
using WString = std::wstring;

class Headers
{
	friend class NetworkReply;
public:
	Headers() {}

	Headers(const Header& strMap)
	{
		for (auto& i : strMap)strHeader.emplace(i.first, i.second);
	}

	Headers(const char* strText, const char* strValue)
	{
		strHeader.emplace(strText, strValue);
	}
	void SetHandle(Header& strMap)
	{
		strHeader = strMap;
	}
	void setRawHeader(std::string strText, std::string strValue)
	{
		strHeader.emplace(strText, strValue);
	}

	operator bool()const
	{
		return strHeader.empty()==true;
	}

	~Headers() {}
private:
	Header strHeader;
};

enum NetworkError { ERROR_NOERROR, ERROR_CRACK, ERROR_CONNECT, ERROR_REQUEST, ERROR_ADDHEADER, ERROR_SEND, ERROR_READ };
//返回值
class NetworkReply
{
public:
	NetworkReply();
	~NetworkReply();

	bool CrackURL(const char* strUrl);//解析url
	bool Connect(HINTERNET hSession);
	bool Request(bool Mode);//post get
	bool AddHeaders(const Headers& header);//添加头
	bool SendRequest(const char* strData);//发送
	bool readAll();

	WCHAR* GetHeader();//获取buffer
	char* GetBuffer()const;
	HString GetUtf8Buffer() const;

	NetworkError Error() const;
	//分割头部到map
	Headers rawHeaderList();

	unsigned int GetSize() const
	{
		return responData->size();
	}
protected:
	WCHAR resHeader[4096];
	std::shared_ptr< std::vector<char>> responData = nullptr;
private:
	HINTERNET hConnect = NULL;
	HINTERNET hRequest = NULL;

	NetworkError dwError;
	bool HttpMode = true;

	unsigned int m_dwServiceType;//连接类型
	INTERNET_PORT m_Port;//端口
	WCHAR m_strHostName[256],
		m_stUrlPath[256];
};


class CHttpClient
{
public:
	CHttpClient();
	~CHttpClient();

	NetworkReply HttpGet(const char* strUrl, Headers& HttpHandle);
	NetworkReply HttpPost(const char* strUrl, Headers& HttpHandle, const char* strData);

	void SetTimeOut(int nTime);
	void SetProxy(LPCWSTR strText);
protected:

private:
	HINTERNET  hSession;
};
#include "pch.h"
#include "CHttpClient.h"
#pragma comment(lib, "winhttp.lib")


void ConvertUtf8ToGBK(std::string& str)
{
	std::string strtemp;

	int len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)str.c_str(), -1, NULL, 0);
	WCHAR* wszGBK = new WCHAR[len];
	memset(wszGBK, 0, len * 2);
	MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)str.c_str(), -1, wszGBK, len);


	len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
	char* szGBK = new char[len];
	memset(szGBK, 0, len);
	WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);

	str = szGBK;
	delete[] szGBK;
	delete[] wszGBK;
}

void ConvertGBKToUtf8(std::string& strGBK)
{
	int len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)strGBK.c_str(), -1, NULL, 0);
	WCHAR* wszUtf8 = new WCHAR[len];
	memset(wszUtf8, 0, len * 2);
	MultiByteToWideChar(CP_ACP, 0, (LPCSTR)strGBK.c_str(), -1, wszUtf8, len);

	len = WideCharToMultiByte(CP_UTF8, 0, wszUtf8, -1, NULL, 0, NULL, NULL);
	char* szUtf8 = new char[len];
	memset(szUtf8, 0, len);
	WideCharToMultiByte(CP_UTF8, 0, wszUtf8, -1, szUtf8, len, NULL, NULL);
	strGBK = szUtf8;
	delete[] szUtf8;
	delete[] wszUtf8;
}

std::wstring s2ws(const std::string& s)
{
	int len;
	int slength = (int)s.length() + 1;
	len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
	wchar_t* buf = new wchar_t[len];
	MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
	std::wstring r(buf);
	delete[] buf;
	return r;
}

CHttpClient::CHttpClient() :hSession(NULL)
{
	hSession = ::WinHttpOpen(L"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", NULL, NULL, NULL, NULL);
}

CHttpClient::~CHttpClient()
{
	if (hSession)
	{
		WinHttpCloseHandle(hSession);
	}
}

NetworkReply CHttpClient::HttpGet(const char* strUrl, Headers& HttpHandle)
{
	NetworkReply lReply;
	if (lReply.CrackURL(strUrl))
	{
		if (lReply.Connect(hSession))
		{
			if (lReply.Request(true))
			{
				HttpHandle.setRawHeader("Accept", "*/*");
				HttpHandle.setRawHeader("Accept-Language", "zh-CN,zh;q=0.9");
				if (lReply.AddHeaders(HttpHandle))
				{
					if (lReply.SendRequest(""))
					{
						lReply.readAll();
					}
				}
			}
		}
	}
	return lReply;
}

NetworkReply CHttpClient::HttpPost(const char* strUrl, Headers& HttpHandle, const char* strData)
{
	NetworkReply lReply;
	if (lReply.CrackURL(strUrl))
	{
		if (lReply.Connect(hSession))
		{
			if (lReply.Request(false))
			{
				HttpHandle.setRawHeader("Accept", "*/*");
				HttpHandle.setRawHeader("Accept-Language", "zh-CN,zh;q=0.9");
				HttpHandle.setRawHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
				if (lReply.AddHeaders(HttpHandle))
				{
					if (lReply.SendRequest(strData))
					{
						lReply.readAll();
					}
				}
			}
		}
	}
	return lReply;
}

void CHttpClient::SetTimeOut(int nTime)
{
	::WinHttpSetTimeouts(hSession, 5000, 5000, 5000, 5000 * 2);
}

void CHttpClient::SetProxy(LPCWSTR strText)
{
	WINHTTP_PROXY_INFO proxy = { 0 };
	proxy.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;

	proxy.lpszProxy = lstrcatW(L"http://", strText);
	WinHttpSetOption(hSession, WINHTTP_OPTION_PROXY, &proxy, sizeof(proxy));
}

NetworkReply::NetworkReply()
	:hConnect(NULL), hRequest(NULL)
{
	dwError = NetworkError::ERROR_NOERROR;
	memset(m_strHostName, 0L, 256);
	memset(m_stUrlPath, 0L, 256);
	memset(resHeader, 0L, 4096);
}

NetworkReply::~NetworkReply()
{
	if (hConnect)
	{
		WinHttpCloseHandle(hConnect);
	}
	if (hRequest)
	{
		WinHttpCloseHandle(hRequest);
	}
}

bool NetworkReply::CrackURL(const char* strUrl)
{
	URL_COMPONENTS urlComp;
	DWORD dwUrlLen = 0;

	ZeroMemory(&urlComp, sizeof(urlComp));
	urlComp.dwStructSize = sizeof(urlComp);
	urlComp.lpszHostName = m_strHostName;
	urlComp.lpszUrlPath = m_stUrlPath;

	urlComp.dwSchemeLength = (DWORD)-1;
	urlComp.dwExtraInfoLength = (DWORD)-1;
	urlComp.dwHostNameLength = 256;
	urlComp.dwUrlPathLength = 256;

	auto strText = s2ws(strUrl);
	if (WinHttpCrackUrl(strText.c_str(), strText.length(), 0, &urlComp))
	{
		lstrcatW(m_stUrlPath, urlComp.lpszExtraInfo);
		m_Port = urlComp.nPort;
		m_dwServiceType = urlComp.nScheme;
		return true;
	}
	dwError = NetworkError::ERROR_CRACK;
	return false;
}

bool NetworkReply::Connect(HINTERNET hSession)
{
	hConnect = WinHttpConnect(hSession, m_strHostName, m_Port, 0);
	if (hConnect == NULL)
	{
		dwError = NetworkError::ERROR_CONNECT;
		return false;
	}
	return true;
}

bool NetworkReply::Request(bool Mode)
{
	HttpMode = Mode;
	auto Ver = HttpMode ? L"GET" : L"POST";
	if (m_dwServiceType == 1)
	{
		hRequest = WinHttpOpenRequest(hConnect, Ver, m_stUrlPath, L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, NULL);
	}
	else
	{
		hRequest = WinHttpOpenRequest(hConnect, Ver, m_stUrlPath, L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
		DWORD dwFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE |
			SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
		WinHttpSetOption(hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &dwFlags, sizeof(dwFlags));
	}

	if (hRequest == NULL)
	{
		dwError = NetworkError::ERROR_REQUEST;
		return false;
	}
	return true;
}

bool NetworkReply::AddHeaders(const Headers& header)//需要测试
{
	if (header)
	{
		return true;
	}
	for (auto& i : header.strHeader)
	{
		auto strText = s2ws(i.first + ": " + i.second + "\r\n");
		if (!WinHttpAddRequestHeaders(hRequest, strText.c_str(), strText.length(), WINHTTP_ADDREQ_FLAG_ADD))
		{
			dwError = NetworkError::ERROR_ADDHEADER;
			return false;
		}
	}
	return true;
}

bool NetworkReply::SendRequest(const char* strData)
{
	if (HttpMode == true) {
		if (WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, WINHTTP_NO_REQUEST_DATA, NULL, NULL, NULL))
		{
			return true;
		}
	}
	else {
		std::string str = strData;
		ConvertGBKToUtf8(str);
		if (WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, (LPVOID)str.c_str(), str.length(), str.length(), 0))
		{
			return true;
		}
	}
	dwError = NetworkError::ERROR_SEND;
	return false;
}

bool NetworkReply::readAll()
{
	bool bResults = WinHttpReceiveResponse(hRequest, NULL);
	if (bResults)
	{
		DWORD dwSize = 0;
		WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, NULL, &dwSize, WINHTTP_NO_HEADER_INDEX);
		if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
			//(3) 使用WinHttpQueryHeaders获取header信息
			bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, resHeader, &dwSize, WINHTTP_NO_HEADER_INDEX);

			if (bResults)
			{
				std::vector<char> tempBuffer;
				DWORD dwDownloaded = 0; //实际收取的字符数
				DWORD dwOffset = 0;

				do {
					dwSize = 0;
					bResults = WinHttpQueryDataAvailable(hRequest, &dwSize);
					if (!bResults) {
						break;
					}
					if (!dwSize)
					{
						break;
					}
						
					//(3) 通过WinHttpReadData读取服务器的返回数据
					tempBuffer.resize(dwOffset + dwSize + 1);

					bResults = WinHttpReadData(hRequest, &tempBuffer[dwOffset], dwSize, &dwDownloaded);
					if (!bResults) {
						break;
					}
					dwOffset += dwSize;
					if (!dwDownloaded)
						break;
				} while (dwSize > 0);
				responData = std::make_shared<std::vector<char>>(tempBuffer);
			}
		}
	}
	if (bResults == false)
	{
		dwError = NetworkError::ERROR_READ;
	}
	return bResults;
}

WCHAR* NetworkReply::GetHeader()
{
	return resHeader;
}

char* NetworkReply::GetBuffer() const
{
	return responData->data();
}

HString NetworkReply::GetUtf8Buffer() const
{
	HString str = responData->data();
	ConvertUtf8ToGBK(str);
	return str;
}

NetworkError NetworkReply::Error() const
{
	return dwError;
}


Headers NetworkReply::rawHeaderList()
{

	return Headers();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值