REST是一種架構(gòu)風(fēng)格,利用HTTP協(xié)議中的GET、POST、PUT、DELETE等方法與服務(wù)器交互,通常用于客戶端和服務(wù)器之間的數(shù)據(jù)交換。REST API通信的核心在于定義資源,客戶端通過URL訪問服務(wù)器上的資源,并通過HTTP方法操作這些資源。

3. C++構(gòu)建服務(wù)端和C#構(gòu)建客戶端實(shí)現(xiàn)雙向交互

1. C++構(gòu)建Restful服務(wù)端

Boost 是一個(gè)廣受歡迎的 C++ 開源庫集合,提供了諸多用于跨平臺(tái)開發(fā)的實(shí)用工具。Boost 涵蓋了從算法到 I/O、正則表達(dá)式、容器和多線程等多種功能,尤其適合構(gòu)建高性能的服務(wù)器、網(wǎng)絡(luò)和系統(tǒng)應(yīng)用。我們就使用 Boost庫構(gòu)建一個(gè) RESTful 風(fēng)格的 C++ Web API。

1.1 Boost庫的核心依賴

我們主要使用兩個(gè)核心庫:

  1. 1. Boost.Asio:提供跨平臺(tái)的異步 I/O 功能,適用于構(gòu)建高效的 TCP、UDP 等網(wǎng)絡(luò)應(yīng)用。
  2. 2.?Boost.Beast:基于 Boost.Asio 實(shí)現(xiàn)的 HTTP 和 WebSocket 協(xié)議庫,簡(jiǎn)化了 RESTful API 的構(gòu)建。

通過vcpkg命令安裝 Boost.Asio庫

vcpkg install boost-asio

通過vcpkg命令安裝 Boost.Beast庫

vcpkg install boost-beast

1.2 構(gòu)建 RESTful C++ Web API

使用 Boost.Beast 構(gòu)建一個(gè)簡(jiǎn)單的 RESTful API 服務(wù),支持基本的 CRUD(創(chuàng)建、讀取、更新、刪除)操作。我們的 API 將運(yùn)行在端口 8080 上,支持以下路徑:

1.3 編碼實(shí)現(xiàn)服務(wù)端代碼

#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <iostream>
#include <string>
#include <thread>

namespace asio = boost::asio;
namespace beast = boost::beast;
namespace http = beast::http;
using tcp = asio::ip::tcp;

std::string data_store = "Sample data"; // 簡(jiǎn)單的數(shù)據(jù)存儲(chǔ)

// 處理 HTTP 請(qǐng)求的函數(shù)
void handle_request(const http::request<http::string_body>& req, http::response<http::string_body>& res) {
if (req.method() == http::verb::get && req.target() == "/api/data") {
res.result(http::status::ok);
res.set(http::field::content_type, "application/json");
res.body() = R"({"data": ")" + data_store + R"("})";
}
else if (req.method() == http::verb::post && req.target() == "/api/data") {
data_store = req.body();
res.result(http::status::created);
res.set(http::field::content_type, "application/json");
res.body() = R"({"message": "Data created"})";
}
else if (req.method() == http::verb::put && req.target() == "/api/data") {
data_store = req.body();
res.result(http::status::ok);
res.set(http::field::content_type, "application/json");
res.body() = R"({"message": "Data updated"})";
}
else if (req.method() == http::verb::delete_ && req.target() == "/api/data") {
data_store.clear();
res.result(http::status::ok);
res.set(http::field::content_type, "application/json");
res.body() = R"({"message": "Data deleted"})";
}
else {
res.result(http::status::not_found);
res.set(http::field::content_type, "application/json");
res.body() = R"({"error": "Resource not found"})";
}
res.prepare_payload();
}

// 會(huì)話處理
void session(tcp::socket socket) {
beast::flat_buffer buffer;
http::request<http::string_body> req;
http::response<http::string_body> res;

try {
http::read(socket, buffer, req);
handle_request(req, res);
http::write(socket, res);
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}

// 主程序啟動(dòng)服務(wù)器
int main() {
try {
asio::io_context ioc;
tcp::acceptor acceptor(ioc, tcp::endpoint(tcp::v4(), 8080));
std::cout << "Server running on http://localhost:8080\n";

while (true) {
tcp::socket socket(ioc);
acceptor.accept(socket);
std::thread(&session, std::move(socket)).detach();
}
} catch (const std::exception& e) {
std::cerr << "Server error: " << e.what() << std::endl;
}
return 0;
}

1.4 啟動(dòng)服務(wù)程序

訪問地址:http://localhost:8080/

訪問地址:http://localhost:8080/api/data

2. 構(gòu)建C#客戶端調(diào)用C++ RESTful API

使用 C# 的 HttpClient 調(diào)用 C++ RESTful API 并進(jìn)行數(shù)據(jù)交互。

2.1 編碼實(shí)現(xiàn)客戶端代碼

using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace CppWebApiClient
{
class Program
{
private static readonly HttpClient client = new HttpClient();

static async Task Main(string[] args)
{
// GET 請(qǐng)求
HttpResponseMessage response = await client.GetAsync("http://localhost:8080/api/data");
string getData = await response.Content.ReadAsStringAsync();
Console.WriteLine("GET Response: " + getData);

// POST 請(qǐng)求
string newData = "\"New sample data\"";
response = await client.PostAsync("http://localhost:8080/api/data", new StringContent(newData, Encoding.UTF8, "application/json"));
Console.WriteLine("POST Response: " + await response.Content.ReadAsStringAsync());

// PUT 請(qǐng)求
string updateData = "\"Updated data\"";
response = await client.PutAsync("http://localhost:8080/api/data", new StringContent(updateData, Encoding.UTF8, "application/json"));
Console.WriteLine("PUT Response: " + await response.Content.ReadAsStringAsync());

// DELETE 請(qǐng)求
response = await client.DeleteAsync("http://localhost:8080/api/data");
Console.WriteLine("DELETE Response: " + await response.Content.ReadAsStringAsync());

Console.ReadKey();
}
}
}

啟動(dòng)客戶端程序

訪問地址:http://localhost:8080/api/data

數(shù)據(jù)已被刪除。

4. C++構(gòu)建客戶端和C#構(gòu)建服務(wù)端實(shí)現(xiàn)雙向交互

我們將通過兩個(gè)部分來構(gòu)建一個(gè)RESTful風(fēng)格的API服務(wù)(使用ASP.NET Core WebAPI)以及如何在C++中調(diào)用這個(gè)WebAPI。

1. 構(gòu)建ASP.NET Core WebAPI服務(wù)

  1. 創(chuàng)建ASP.NET Core WebAPI項(xiàng)目
dotnet new webapi -n MyApi
cd MyApi

2.?定義一個(gè)簡(jiǎn)單的Controller?我們創(chuàng)建一個(gè)簡(jiǎn)單的Controller?ProductsController.cs,提供幾個(gè)GET和POST的接口

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace MyApi.Controllers
{
public class ProductRequest
{
public string Product { get; set; }
}
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
// 這是一個(gè)存儲(chǔ)產(chǎn)品的示例
private static readonly List<string> Products = new List<string>
{
"Product1",
"Product2",
"Product3"
};
// 獲取所有產(chǎn)品
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return Ok(Products);
}
// 獲取單個(gè)產(chǎn)品
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
if (id < 0 || id >= Products.Count)
{
return NotFound();
}
return Ok(Products[id]);
}
// 創(chuàng)建新產(chǎn)品
[HttpPost]
public ActionResult Post([FromBody] ProductRequest product)
{
if (string.IsNullOrEmpty(product?.Product))
{
return BadRequest("Product cannot be empty");
}

Products.Add(product.Product);
return CreatedAtAction(nameof(Get), new { id = Products.Count - 1 }, product);
}
}
}

3.?運(yùn)行API?在命令行中,運(yùn)行以下命令啟動(dòng)API服務(wù)器:

dotnet run

2. 構(gòu)建C++客戶端調(diào)用WebAPI

現(xiàn)在,我們已經(jīng)創(chuàng)建了一個(gè)基本的WebAPI服務(wù)。接下來,我們將在C++中編寫代碼,通過HTTP請(qǐng)求來調(diào)用這個(gè)WebAPI。為了發(fā)送HTTP請(qǐng)求,C++沒有內(nèi)置的庫,因此我們將使用一些第三方庫,如libcurl

  1. 安裝libcurl庫?可以從libcurl官網(wǎng)[1]下載并安裝。或者通過vcpkg安裝?vcpkg install curl

2.?C++代碼:使用libcurl調(diào)用WebAPI在C++中,我們將使用libcurl庫來發(fā)送HTTP請(qǐng)求。

#include <iostream>
#include <string>
#include <curl/curl.h>
// 回調(diào)函數(shù),用于處理HTTP響應(yīng)數(shù)據(jù)
size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
size_t totalSize = size * nmemb;
((std::string*)userp)->append((char*)contents, totalSize);
return totalSize;
}
// GET請(qǐng)求
void GetProducts() {
CURL* curl;
CURLcode res;
std::string readBuffer;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:5056/api/products");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
// 執(zhí)行請(qǐng)求
res = curl_easy_perform(curl);
// 檢查請(qǐng)求是否成功
if (res != CURLE_OK) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
}
else {
std::cout << "Response: " << readBuffer << std::endl;
}
curl_easy_cleanup(curl);
}
curl_global_cleanup();
}

// POST請(qǐng)求
void AddProduct(const std::string& product) {
CURL* curl;
CURLcode res;
std::string readBuffer;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl) {
// 設(shè)置URL
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:5056/api/products");
// 設(shè)置HTTP頭
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json");
// 設(shè)置POST數(shù)據(jù)
std::string jsonData = "{\"product\":\"" + product + "\"}";
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());
// 處理響應(yīng)
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
// 執(zhí)行請(qǐng)求
res = curl_easy_perform(curl);
// 檢查請(qǐng)求是否成功
if (res != CURLE_OK) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
}
else {
std::cout << "Response: " << readBuffer << std::endl;
}
curl_easy_cleanup(curl);
curl_slist_free_all(headers);
}
curl_global_cleanup();
}
int main() {
// 獲取所有產(chǎn)品
GetProducts();
// 添加新產(chǎn)品
AddProduct("Product4");
// 獲取所有產(chǎn)品,查看是否添加成功
GetProducts();
int i;
std::cin >> i;
return 0;
}

3.?編譯并運(yùn)行C++代碼

5. 注意事項(xiàng)

  1. 安全性:在生產(chǎn)環(huán)境中,請(qǐng)使用SSL證書,確保API通信的安全性。在開發(fā)環(huán)境中可以臨時(shí)禁用SSL驗(yàn)證。
  2. 數(shù)據(jù)格式:通常REST API使用JSON格式傳遞數(shù)據(jù),便于解析。
  3. 錯(cuò)誤處理:在生產(chǎn)中,要添加錯(cuò)誤處理,捕獲網(wǎng)絡(luò)問題和API錯(cuò)誤狀態(tài)碼,確保程序穩(wěn)定性。

6. 應(yīng)用場(chǎng)景

7. 優(yōu)缺點(diǎn)

8. 總結(jié)

REST API 提供了一種靈活且標(biāo)準(zhǔn)化的通信方式,能夠在不同語言和平臺(tái)間實(shí)現(xiàn)通信。通過本文的示例代碼,C++ 和 C# 程序可以借助 REST API 實(shí)現(xiàn)數(shù)據(jù)交互。這種方法尤其適合分布式應(yīng)用和微服務(wù)架構(gòu)的設(shè)計(jì)。在下一篇中,我們將介紹gRPC,這是一個(gè)高效的跨平臺(tái)通信協(xié)議,非常適合高性能需求的場(chǎng)景。

文章轉(zhuǎn)自微信公眾號(hào)@dotnet研習(xí)社

上一篇:

構(gòu)建現(xiàn)代RESTful API:C#中的關(guān)鍵標(biāo)準(zhǔn)和最佳實(shí)踐

下一篇:

把 C# 里的 HttpClient 封裝起來,告別復(fù)雜的配置,讓 Restful API 調(diào)用更輕松更高效
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)