当前位置: 首页 > 工具软件 > Restbed > 使用案例 >

restbed -C++ restfull 架构的应用

米夕
2023-12-01

       C++ 编写的嵌入式应用程序,需要通过Web 服务器作为UI。用C++ 实现restfull web service 程序。我选择了restbed 架构(https://github.com/corvusoft/restbed)。

安装

我使用的是windows WSL 形式的ubuntu OS,github 上安装讲的非常简单。

git clone --recursive https://github.com/corvusoft/restbed.git
mkdir restbed/build
cd restbed/build
cmake [-DBUILD_SSL=NO] ..
sudo make install
make test

实际安装过程中遇到了一些麻烦

  1. 我在在window 10 的WSL上安装的,预先要安装cmake
  2. 这个库是C++库,所以要使用 GCC++,或者是Clang。所以我预先安装了Clang。
  3. 在cmake [-DBUILD_SSL=NO] 过程中遇到了openssl编译方面的问题。后改为预先编译openssl。
sudo apt-get install libssl-dev
cd dependency/openssl
./config
make

在ubuntu 采取上述方式安装,也成功的。

应用程序的编译

编译应用程序的过程中发现缺少 libc++库,ssl库缺少的问题。

sudo apt-get update
sudo apt-get install libc++-dev
sudo apt-get install libssl-dev

restbed 程序make install 出来的include 和lib 放置在了restbed/distribution 目录下。要将include的内容 拷贝到 usr/include 中,而静态库librestbed.a 拷贝到应用程序的目录下。

我们编写了一个简单的应用程序 restbed_get.cpp 编译过程中要使用ssl,cryoto 和pthread 三个库。

sudo clang++ restbed_get.cpp   -L./ -l restbed -o restbed_get -lssl -lcrypto –lpthread

 

实例1

restfull的机制是web 服务。所以在restbed 中,服务(service)是一个重要的对象。他可以发布一个资源(resource)。restfull API 就是给其它机器提供一个使用HTTP协议调用这些服务的机制。

#include <string>
#include <memory>
#include <cstdlib>
#include <fstream>
#include <restbed>
#include <streambuf>

using namespace std;
using namespace restbed;

void get_method_handler( const shared_ptr< Session > session )
{
    const auto request = session->get_request( );
    const string filename = request->get_path_parameter( "filename" );
    
    ifstream stream( "./" + filename, ifstream::in );
    
    if ( stream.is_open( ) )
    {
        const string body = string( istreambuf_iterator< char >( stream ), istreambuf_iterator< char >( ) );
        
        const multimap< string, string > headers
        {
            { "Content-Type", "text/html" },
            { "Content-Length", ::to_string( body.length( ) ) }
        };
        
        session->close( OK, body, headers );
    }
    else
    {
        session->close( NOT_FOUND );
    }
}

int main( const int, const char** )
{
    auto resource = make_shared< Resource >( );
    resource->set_path( "/static/{filename: [a-z]*\\.html}" );
    resource->set_method_handler( "GET", get_method_handler );
    
    auto settings = make_shared< Settings >( );
    settings->set_port( 1984 );
    settings->set_default_header( "Connection", "close" );
    
    Service service;
    service.publish( resource );
    service.start( settings );
    
    return EXIT_SUCCESS;
}

测试

在程序的文件夹中丢一个index.html 文件

在浏览器上键入:http://localhost:1984/static/index.html,出现hello the world 的页面。

实例2

这个程序于实际应用更加接近一点。

定义了三个resource。可以调用html ,css 文档和web API 参数传递。

#include <string>
#include <memory>
#include <cstdlib>
#include <fstream>
#include <restbed>
#include <streambuf>

using namespace std;
using namespace restbed;

void get_index( const shared_ptr< Session > session )
{
   // const auto request = session->get_request( );
    
    ifstream stream( "./index.html", ifstream::in );
    
    if ( stream.is_open( ) )
    {
        const string body = string( istreambuf_iterator< char >( stream ), istreambuf_iterator< char >( ) );
        
        const multimap< string, string > headers
        {
            { "Content-Type", "text/html" },
            { "Content-Length", ::to_string( body.length( ) ) }
        };
        
        session->close( OK, body, headers );
    }
    else
    {
        session->close( NOT_FOUND );
    }
}
void get_css( const shared_ptr< Session > session )
{
     const auto request = session->get_request( );
    
     const string filename = request->get_path_parameter( "filename" );
    
     ifstream stream( "./" + filename, ifstream::in );
    
    if ( stream.is_open( ) )
    {
        const string body = string( istreambuf_iterator< char >( stream ), istreambuf_iterator< char >( ) );
        
        const multimap< string, string > headers
        {
            { "Content-Type", "text/css" },
            { "Content-Length", ::to_string( body.length( ) ) }
        };
        
        session->close( OK, body, headers );
    }
    else
    {
        session->close( NOT_FOUND );
    }
}
void get_value( const shared_ptr< Session > session )
{
	const auto request = session->get_request( );   
	const string id = request->get_query_parameter( "id" );
	const string val = request->get_query_parameter( "val" );
	  const string body = "id="+id+",val="+val;
	   session->close( OK, body, { { "Content-Length", ::to_string( body.size( ) ) } } );
}
int main( const int, const char** )
{
    auto resource1 = make_shared< Resource >( );
    resource1->set_path( "/index" );
    resource1->set_method_handler( "GET", get_index );
    
	auto resource2 = make_shared< Resource >( );
    resource2->set_path( "/css/{filename: [a-z]*\\.css}" );
    resource2->set_method_handler( "GET", get_css); 
	
	auto resource3 = make_shared< Resource >( );
    resource3->set_path( "/query/param");
    resource3->set_method_handler( "GET", get_value); 
   
   auto settings = make_shared< Settings >( );
    settings->set_port( 1984 );
    settings->set_default_header( "Connection", "close" );
         
    Service service;
    service.publish( resource1 );
	service.publish( resource2 );
	service.publish( resource3 );
    service.start( settings ); 
    return EXIT_SUCCESS;
}

遇到的问题

在传递参数时遇到了些问题,花费了许多时间。

HTTP 请求向服务器端提供参数,具体的方式有两种:

1 路径参数方式

Path parameter example: http://localhost:8080/v1/api/customer/1,2,3/policy

2 查询参数方式

Query parameter example: http://localhost:8080/v1/api/customer?id=1,2,3

   在restbed 中的实例中,多数使用的是path parameters。使用Query parameter 不知道如何使用,试了许多方法都不对。最后搞定了。只要记得一件事:?前面的是path parameter,而?后面的是query parameter。

例如在“http://localhost:8080/v1/api/customer?id=1,2,3”中,具体的做法是

resource->set_path( "/v1/api/customer ");

而在 get_method_handle 子程序中使用

const string parameters = request->get_query_parameter( "id" );

至此,restbed 基本好用了。

 类似资料: