SkillAgentSearch skills...

Cinatra

C++20 实现的跨平台、header only,易用的高性能http库; modern c++(c++20), cross-platform, header-only, easy to use http framework

Install / Use

/learn @qicosmos/Cinatra
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

cinatra--一个高效易用的c++ http框架

<p align="center"> <a href="https://github.com/qicosmos/cinatra/tree/master/lang/english">English</a> | <span>中文</span> </p>

| OS (Compiler Version) | Status | |------------------------------------------------|----------------------------------------------------------------------------------------------------------| | Ubuntu 22.04 (clang 14.0.0) | win | | Ubuntu 22.04 (gcc 11.2.0) | win | | macOS Monterey 12 (AppleClang 14.0.0.14000029) | win | | Windows Server 2022 (MSVC 19.33.31630.0) | win |

目录

使用cinatra常见问题汇总(FAQ)

基于C++20 协程的http库

cinatra简介

cinatra是一个高性能易用的http框架,它是用modern c++(c++20)开发的,它的目标是提供一个快速开发的c++ http框架。它的主要特点如下:

  1. 统一而简单的接口
  2. header-only
  3. 跨平台
  4. 高效
  5. 支持面向切面编程

cinatra目前支持了http1.1/1.0, ssl和websocket, 你可以用它轻易地开发一个http服务器,比如常见的数据库访问服务器、文件上传下载服务器、实时消息推送服务器,你也可以基于cinatra开发一个mqtt服务器。 cinatra是世界上性能最好的http服务器之一,性能测试详见性能测试

除此之外,cinatra 还提供了一个基于C++20 协程的http(https) client,包括普通get/post请求、文件上传下载和web socket、redirect、proxy等功能。

谁在用cinatra

cinatra目前被很多公司在使用,在这里可以看到谁在用cinatra.

如何使用

编译器版本

  1. C++20 编译器 (gcc 10.2, clang 13, Visual Studio 2022,或者更高的版本)

使用

cinatra是header-only的,引用include头文件目录,并设置如下编译选项:

如果 linux, 设置:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -std=c++20")

如果 g++ 编译,再设置:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines")

set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-tree-slp-vectorize")

cinatra指令集功能使用

cinatra支持通过指令集优化其内部逻辑,其通过宏来控制是否使用指令集。使用之前请确保cpu支持。

使用如下命令即可编译带simd优化的cinatra。注意只能开启一种simd指令集优化,开启多个会导致编译失败。

cmake -DENABLE_SIMD=SSE42 .. # 启用sse4.2指令集
cmake -DENABLE_SIMD=AVX2 .. # 启用avx2指令集
cmake -DENABLE_SIMD=AARCH64 .. # arm环境下,启用neon指令集

快速示例

示例1:一个简单的hello world

	#include "include/cinatra.hpp"
	using namespace cinatra;
	
	int main() {
		int max_thread_num = std::thread::hardware_concurrency();
		coro_http_server server(max_thread_num, 8080);
		server.set_http_handler<GET, POST>("/", [](coro_http_request& req, coro_http_response& res) {
			res.set_status_and_content(status_type::ok, "hello world");
		});

		server.sync_start();
		return 0;
	}

5行代码就可以实现一个简单http服务器了,用户不需要关注多少细节,直接写业务逻辑就行了。

示例2:基本用法

#include "cinatra.hpp"

struct person_t {
  void foo(coro_http_request &, coro_http_response &res) {
    res.set_status_and_content(status_type::ok, "ok");
  }
};

async_simple::coro::Lazy<void> basic_usage() {
  coro_http_server server(1, 9001);
  server.set_http_handler<GET>(
      "/get", [](coro_http_request &req, coro_http_response &resp) {
        resp.set_status_and_content(status_type::ok, "ok");
      });

  server.set_http_handler<GET>(
      "/coro",
      [](coro_http_request &req,
         coro_http_response &resp) -> async_simple::coro::Lazy<void> {
        resp.set_status_and_content(status_type::ok, "ok");
        co_return;
      });

  server.set_http_handler<GET>(
      "/in_thread_pool",
      [](coro_http_request &req,
         coro_http_response &resp) -> async_simple::coro::Lazy<void> {
        // will respose in another thread.
        co_await coro_io::post([&] {
          // do your heavy work here when finished work, response.
          resp.set_status_and_content(status_type::ok, "ok");
        });
      });

  server.set_http_handler<POST, PUT>(
      "/post", [](coro_http_request &req, coro_http_response &resp) {
        auto req_body = req.get_body();
        resp.set_status_and_content(status_type::ok, std::string{req_body});
      });

  server.set_http_handler<GET>(
      "/headers", [](coro_http_request &req, coro_http_response &resp) {
        auto name = req.get_header_value("name");
        auto age = req.get_header_value("age");
        assert(name == "tom");
        assert(age == "20");
        resp.set_status_and_content(status_type::ok, "ok");
      });

  server.set_http_handler<GET>(
      "/query", [](coro_http_request &req, coro_http_response &resp) {
        auto name = req.get_query_value("name");
        auto age = req.get_query_value("age");
        assert(name == "tom");
        assert(age == "20");
        resp.set_status_and_content(status_type::ok, "ok");
      });

  server.set_http_handler<cinatra::GET, cinatra::POST>(
      "/users/:userid/subscriptions/:subid",
      [](coro_http_request &req, coro_http_response &response) {
        assert(req.params_["userid"] == "ultramarines");
        assert(req.params_["subid"] == "guilliman");
        response.set_status_and_content(status_type::ok, "ok");
      });

  person_t person{};
  server.set_http_handler<GET>("/person", &person_t::foo, person);

  server.async_start();
  std::this_thread::sleep_for(300ms);  // wait for server start

  coro_http_client client{};
  auto result = co_await client.async_get("http://127.0.0.1:9001/get");
  assert(result.status == 200);
  assert(result.resp_body == "ok");
  for (auto [key, val] : result.resp_headers) {
    std::cout << key << ": " << val << "\n";
  }

  result = co_await client.async_get("/coro");
  assert(result.status == 200);

  result = co_await client.async_get("/in_thread_pool");
  assert(result.status == 200);

  result = co_await client.async_post("/post", "post string",
                                      req_content_type::string);
  assert(result.status == 200);
  assert(result.resp_body == "post string");

  client.add_header("name", "tom");
  client.add_header("age", "20");
  result = co_await client.async_get("/headers");
  assert(result.status == 200);

  result = co_await client.async_get("/query?name=tom&age=20");
  assert(result.status == 200);

  result = co_await client.async_get(
      "http://127.0.0.1:9001/users/ultramarines/subscriptions/guilliman");
  assert(result.status == 200);

  // make sure you have installed openssl and enable CINATRA_ENABLE_SSL
#ifdef CINATRA_ENABLE_SSL
  coro_http_client client2{};
  result = co_await client2.async_get("https://baidu.com");
  assert(result.status == 200);
#endif
}

int main() {
  async_simple::coro::syncAwait(basic_usage());
}

示例3:面向切面的http服务器

	#include "cinatra.hpp"
	using namespace cinatra;

	//日志切面
	struct log_t
	{
		bool before(coro_http_request& req, coro_http_response& res) {
			std::cout << "before log" << std::endl;
			return true;
		}
	
		bool after(coro_http_request& req, coro_http_response& res) {
			std::cout << "after log" << std::endl;
			return true;
		}
	};
	
	//校验的切面
	struct check  {
		bool before(coro_http_request& req, coro_http_response& res) {
			std::cout << "before check" << std::endl;
			if (req.get_header_value("name").empty()) {
				res.set_status_and_content(status_type::bad_request);
				return false;
			}
			return true;
		}
	
		bool after(coro_http_request& req, coro_http_response& res) {
			std::cout << "after check" << std::endl;
			return true;
		}
	};

	//将信息从中间件传输到处理程序
	struct get_data  {
		bool before(coro_http_request& req, coro_http_response& res) {
			req.set_aspect_data("hello world");
			return true;
		}
	}

	int main() {
		coro_http_server server(std::thread::hardware_concurrency(), 8080);
		server.set_http_handler<GET, POST>("/aspect", [](coro_http_request& req, coro_http_response& res) {
			res.set_status_and_content(status_type::ok, "hello world");
		}, check{}, log_t{});

		server.set_http_handler<GET,POST>("/aspect/data", [](coro_http_request& req, coro_http_response& res) {
			auto& val = req.get_aspect_data();
			res.set_status_and_content(status_type::ok, std::move(val[0]));
		}, get_data{});

		server.sync_start();
		return 0;
	}

本例中有两个切面,一个校验http请求的切面,一个是日志切面,这个切面用户可以根据需求任意增加。本例会先检查http请求的合法性,如果不合法就会返回bad request,合法就会进入下一个切面,即日志切面,日志切面会打印出一个before表示进入业务逻辑之前的处理,业务逻辑完成之后会打印after表示业务逻辑结束之后的处理。

示例4:文件上传、下载、websocket

example中的例子

示例5:RESTful服务端路径参数设置

本代码演示如何使用RESTful路径参数。下面设置了两个RESTful API。第一个API当访问,比如访问这样的urlhttp://127.0.0.1:8080/numbers/1234/test/5678时服务器可以获取到1234和5678这两个参数,第一个RESTful API的参数是(\d+)是一个正则表达式表明只能参数只能为数字。获取第一个参数的代码是req.matches_[1]。因为每一个req不同所以每一个匹配到的参数都放在request结构体中。

同时还支持任意字符的RESTful API,即示例的第二种RESTful API"/string/:id/test/:name",要获取到对应的参数使用req.get_query_value函数即可,其参数只能为注册的变量(如果不为依然运行但是有报错),例子中参数名是id和name,要获取id参数调用req.get_query_value("id")即可。示例代码运行后,当访问http://127.0.0.1:8080/string/params_1/test/api_test时,浏览器会返回api_test字符串。

#include "cinatra.hpp"
using namespace cinatra;

int main() {
	int max_thread_num = std::thread::hardware_concurrency();
	coro_http_server server(max_thread_num, 8080);

	server.set_http_handler<GET, POST>(
		R"(/numbers/(\d+)/test/(\d+))", [](request &req, response &res) {
			std::cout << " matches[1] is : " << req.matches_[1]
					<< " matches[2] is: " << req.matches_[2] << std::endl;

			res.set_status_and_content(status_type::ok, "hello world");
		});

	server.set_http_handler<GET, POST>(
		"/string/:id/test/:name", [](request &req, response &res) {
			std::string id = req.get_query_value("id");
			std::cout << "id value is: " << id << std::endl;
			std::cout << "name value is: " << std::string(req.get_query_value("name")) << std::endl;
			res.set_status_and_content(status_type::ok, std::string(req.get_q

Related Skills

View on GitHub
GitHub Stars2.1k
CategoryDevelopment
Updated1d ago
Forks384

Languages

C++

Security Score

95/100

Audited on Mar 27, 2026

No findings