在开发Windows应用程序时,经常需要与REST接口进行交互。虽然市面上有许多SDK可供选择,如Google Drive、Facebook APIs等,但它们通常只提供Java、PHP、Python等语言的SDK,而Windows平台往往被忽视。为了解决这一问题,开发了一个小库,可以快速处理任何REST接口。本文将介绍这个库的基本概念和使用方法。
为了简化编码,封装了HINTERNET WinInet句柄。这个封装类名为ihandle,它提供了复制和移动函数,并且可以作为标准的HINTERNET句柄使用。
class ihandle {
private:
HINTERNET hX = 0;
std::shared_ptr ptr = std::make_shared();
public:
void Close() {
if (!ptr || !ptr.unique()) {
ptr.reset();
return;
}
ptr.reset();
if (hX != 0)
InternetCloseHandle(hX);
hX = 0;
}
ihandle() {
hX = 0;
}
~ihandle() {
Close();
}
ihandle(const ihandle& h) {
Dup(h);
}
ihandle(ihandle&& h) {
Move(std::forward(h));
}
ihandle(HINTERNET hY) {
hX = hY;
}
ihandle& operator=(const ihandle& h) {
Dup(h);
return *this;
}
ihandle& operator=(ihandle&& h) {
Move(std::forward(h));
return *this;
}
void Dup(const ihandle& h) {
Close();
hX = h.hX;
ptr = h.ptr;
}
void Move(ihandle&& h) {
Close();
hX = h.hX;
ptr = h.ptr;
h.ptr.reset();
h.hX = 0;
}
operator HINTERNET() const {
return hX;
}
};
库需要从某个地方读取或写入数据。定义了一个抽象接口data_provider,用于读取数据。为了方便,库提供了两个实现:memory_data_provider和file_data_provider,分别用于从内存缓冲区和文件句柄读取数据。
class data_provider {
public:
virtual size_t s() = 0;
virtual size_t Read(char* Buff, size_t sz) = 0;
virtual bool CanOnce() = 0;
virtual std::tuple Once() = 0;
};
同样地,定义了一个抽象接口data_writer,用于写入数据。库也提供了两个实现:memory_data_writer和file_data_writer,分别用于写入到内存或句柄。
class data_writer {
public:
virtual DWORD Write(const char* Buff, DWORD sz) = 0;
virtual size_t s() = 0;
};
库的构造函数接受代理名称作为参数。可以连接或断开连接,发起请求,并读取结果。
REST(const wchar_t* ag = 0);
HRESULT Connect(const wchar_t* host, bool SSL = false, unsigned short Port = 0, DWORD flg = 0, const wchar_t* user = 0, const wchar_t* pass = 0);
void Disconnect();
ihandle Request2(const wchar_t* url, data_provider& dp, bool Once = true, const wchar_t* verb = L"POST", std::initializer_list hdrs = {}, std::function fx = nullptr, void* lp = 0, const char* extradata1 = 0, DWORD extradatasize1 = 0, const char* extradata2 = 0, DWORD extradatasize2 = 0);
long Headers(ihandle& hI3, std::map& t);
HRESULT Read2(ihandle& hI3, data_writer& dw, std::function fx = nullptr, void* lp = 0);
if (FAILED(Connect(L"accounts.google.com", true))) return false;
string u;
// 构建要作为请求正文传递的内容
u = {...};
wchar_t au[1000] = {0};
swprintf_s(au, 1000, L"Content-Length: %u", (DWORD)u.length());
auto hi = RequestWithBuffer(L"/o/oauth2/token", L"POST", { L"Content-Type: application/x-www-form-urlencoded", au }, u.data(), u.size());
vector out;
ReadToMemory(hi, out);
out.resize(out.size() + 1); // 使其成为ASCIIZ
char* p = (char*)out.data();
j.Parse(p); // 解析为JSON,以提供刷新和访问令牌