簡介
C++ REST SDK 是 Microsoft 的一個開源跨平臺項目( 使用 MIT 開源協議 ), 其使用大量現代異步 C++ API 實現了一個基於 HTTP / HTTPS 協議的 服務端 / 客戶端 組件,使用該組件,可以方便地進行高性能RESTful、HTTP / HTTPS 服務器、客戶端開發,且可以在Windows、Linux、OSX、iOS、Android各平臺下使用,各平臺及功能支持情況如下:
平臺/功能 | Windows | Linux | Mac OSX | iOS | Android |
---|---|---|---|---|---|
並行任務 | 支持 | 支持 | 支持 | 支持 | 支持 |
JSON編解碼 | 支持 | 支持 | 支持 | 支持 | 支持 |
異步流 | 支持 | 支持 | 支持 | 支持 | 支持 |
URIs解析 | 支持 | 支持 | 支持 | 支持 | 支持 |
HTTP客戶端 | 支持 | 支持 | 支持 | 支持 | 支持 |
HTTP監聽(服務端) | (XP以上支持) | 支持 | 支持 | 支持 | 支持 |
WebSocket客戶端 | 支持 | 支持 | 支持 | 支持 | 支持 |
OAuth客戶端 | 支持 | 支持 | 支持 | 支持 | 支持 |
Cpp Rest SDK編譯
官方推薦使用vcpkg下載CPP Rest SDK源碼和編譯,該工具除了可以下載Cpp Rest SDK源碼外還可自動下載相關依賴包,並通過命令行進行自動編譯、向VisualStudio引入相關庫,大大簡化了在自己的項目中使用Cpp Rest SDK的難度。
vcpkg作爲微軟開發的另一款開源代碼管理工具,並未隨Visual Studio 2015安裝在系統中,我們需要手動下載該工具源碼並進行編譯纔可以使用:
(1)通過Git下載vcpkg源碼到一個文件夾下:
git clone https://github.com/Microsoft/vcpkg
(2)在該文件夾運行命令進行編譯:
bootstrap-vcpkg.bat
(3)爲了使vcpkg能自動在VS中添加相關庫引用,在管理員權限下運行:
vcpkg integrate install
(4)重啓命令行,這樣vcpkg就安裝配置好了
(5)在命令行中使用vcpkg下載CPP Rest SDK源碼(注意事項:工作目錄不能含有中文、空格,編譯需要使用英文版的Visual Studio,否則會編譯出錯):
vcpkg install cpprestsdk cpprestsdk:x64-windows
(6)在漫長的等待後,命令行提示全部編譯完成,此時,就可以打開VS新建一個項目試試效果了,以下是一個簡單的HTTP服務器例子:
//main.cpp
#include <iostream>
#include "include/stdafx.h"
#include "include/handler.h"
#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
#include <cpprest/http_listener.h> // HTTP server
#include <cpprest/json.h> // JSON library
#include <cpprest/uri.h> // URI library
#include <cpprest/ws_client.h> // WebSocket client
#include <cpprest/containerstream.h> // Async streams backed by STL containers
#include <cpprest/interopstream.h> // Bridges for integrating Async streams with STL and WinRT streams
#include <cpprest/rawptrstream.h> // Async streams backed by raw pointer to memory
#include <cpprest/producerconsumerstream.h> // Async streams for producer consumer scenarios
using namespace std;
using namespace web;
using namespace http;
using namespace utility;
using namespace http::experimental::listener;
std::unique_ptr<handler> g_httpHandler;
void on_initialize(const string_t& address)
{
uri_builder uri(address);
auto addr = uri.to_uri().to_string();
g_httpHandler = std::unique_ptr<handler>(new handler(addr));
g_httpHandler->open().wait();
ucout << utility::string_t(U("Listening for requests at: ")) << addr << std::endl;
return;
}
void on_shutdown()
{
g_httpHandler->close().wait();
return;
}
#ifdef _WIN32
int wmain(int argc, wchar_t *argv[])
#else
int main(int argc, char *argv[])
#endif
{
utility::string_t port = U("34568");
if(argc == 2)
{
port = argv[1];
}
utility::string_t address = U("http://127.0.0.1:");
address.append(port);
on_initialize(address);
std::cout << "Press ENTER to exit." << std::endl;
std::string line;
std::getline(std::cin, line);
on_shutdown();
return 0;
}
//hander.h
#ifndef HANDLER_H
#define HANDLER_H
#include <iostream>
#include "stdafx.h"
//#include "../dbms/include/Dbms.h"
using namespace std;
using namespace web;
using namespace http;
using namespace utility;
using namespace http::experimental::listener;
class handler
{
public:
handler();
handler(utility::string_t url);
virtual ~handler();
pplx::task<void>open(){return m_listener.open();}
pplx::task<void>close(){return m_listener.close();}
protected:
private:
void handle_get(http_request message);
void handle_put(http_request message);
void handle_post(http_request message);
void handle_delete(http_request message);
void handle_error(pplx::task<void>& t);
http_listener m_listener;
};
#endif // HANDLER_H
//hander.cpp
#include "../include/handler.h"
handler::handler()
{
//ctor
}
handler::handler(utility::string_t url):m_listener(url)
{
m_listener.support(methods::GET, std::bind(&handler::handle_get, this, std::placeholders::_1));
m_listener.support(methods::PUT, std::bind(&handler::handle_put, this, std::placeholders::_1));
m_listener.support(methods::POST, std::bind(&handler::handle_post, this, std::placeholders::_1));
m_listener.support(methods::DEL, std::bind(&handler::handle_delete, this, std::placeholders::_1));
}
handler::~handler()
{
//dtor
}
void handler::handle_error(pplx::task<void>& t)
{
try
{
t.get();
}
catch(...)
{
// Ignore the error, Log it if a logger is available
}
}
//
// Get Request
//
void handler::handle_get(http_request message)
{
ucout << message.to_string() << endl;
auto paths = http::uri::split_path(http::uri::decode(message.relative_uri().path()));
message.relative_uri().path();
//Dbms* d = new Dbms();
//d->connect();
concurrency::streams::fstream::open_istream(U("static/index.html"), std::ios::in).then([=](concurrency::streams::istream is)
{
message.reply(status_codes::OK, is, U("text/html"))
.then([](pplx::task<void> t)
{
try{
t.get();
}
catch(...){
//
}
});
}).then([=](pplx::task<void>t)
{
try{
t.get();
}
catch(...){
message.reply(status_codes::InternalError,U("INTERNAL ERROR "));
}
});
return;
};
//
// A POST request
//
void handler::handle_post(http_request message)
{
ucout << message.to_string() << endl;
message.reply(status_codes::OK,message.to_string());
return ;
};
//
// A DELETE request
//
void handler::handle_delete(http_request message)
{
ucout << message.to_string() << endl;
wstring rep = U("WRITE YOUR OWN DELETE OPERATION");
message.reply(status_codes::OK,rep);
return;
};
//
// A PUT request
//
void handler::handle_put(http_request message)
{
ucout << message.to_string() << endl;
wstring rep = U("WRITE YOUR OWN PUT OPERATION");
message.reply(status_codes::OK,rep);
return;
};
(7)編譯通過後,運行程序,使用瀏覽器訪問如下地址,即可看到服務器已成功運行
http://127.0.0.1:34568
根據上述方法,由於我的編譯環境爲VS2013,導致使用vcpkg是報錯
因此找到了另一種方式,通過VS2013的工具->NuGet包管理器->程序包管理器控制檯
執行命令
install-package cpprestsdk
之後會開始安裝rest sdk
不過這個過程非常慢,可以去下載離線包
https://www.nuget.org/packages?q=cpprestsdk.v120
這裏的每個包都是需要的。
離線包放的位置是在 工具->NuGet程序包管理器->程序包管理器設置 這裏找到
如果瀏覽按鈕是灰色的,是因爲沒安裝過NuGet包,文件夾還沒有創建,可以安裝上圖中的默認位置創建文件夾,也可以到聯機裏安裝一個小的NuGet包,這樣就可以了。