这是我参与8月更文挑战的第13天,活动详情查看:8月更文挑战
今天开始带大家使用Flare框架的,从0开始搭建一个HTTP服务的聊天室。
今天首先试着用flare的http框架,搭建起用户登陆认证的接口。
flare运行环境
flare作为一个fiber微线程框架,首先需要启动整个框架的运行环境,将后台的微线程管理等等线程启动起来,因此main函数中要通过如下的形式启动flare运行环境。
int main(int argc, char** argv) {
return flare::Start(argc, argv, chatroom::Entry);
}
HTTP服务
flare框架提供了一整套的RPC框架,并支持基于Protobuf和HTTP的通信协议,flare中对HTTP的请求的处理通过HttpHandler完成。HttpHandler可以关联至某个URI上,后续框架会将相应的请求转发给这一HttpHandler。
int Entry(int argc, char** argv) {
flare::Server server;
server.AddProtocol("http");
server.AddHttpFilter(std::make_unique<LoginFilter>(flare::detail::UriMatcher(std::regex("^/user(Login([/\?#](.*?))?)?$"))));
server.AddHttpHandler(std::regex("^/user(/.+)?$"), std::make_unique<UserHandler>());
server.AddHttpPrefixHandler("/userLogin", std::make_unique<UserLoginHandler>());
server.ListenOn(flare::EndpointFromIpv4("0.0.0.0", 8080));
FLARE_CHECK(server.Start());
while (!flare::CheckForQuitSignal()) {
flare::this_fiber::SleepFor(1s);
}
server.Stop();
server.Join();
return 0;
}
上面这段程序中
- 创建了一个flare Server对象
- 通过AddProtocol方法设定通信协议是HTTP
AddHttpFilter可以为Http服务添加过滤器AddHttpHandler和AddHttpPrefixHandler的配置,将对应的URI请求转发给绑定的Handler中- ListenOn方法设定HTTP开启的IP和端口
server.Start()方法启动HTTP服务- 通过
flare::CheckForQuitSignal()的方法循环检查程序是否收到退出的信号(ctl+c) - Stop()、Join()等待框架完全停止结束
Handler
下面介绍一下用户登陆的Handler如何实现用户的登陆。首先看一下我们要实现的用户登陆的接口
/userLogin:
get:
tags:
- user
summary: Logs user into the system
operationId: loginUser
parameters:
- name: username
in: query
description: The user name for login
required: true
schema:
type: string
- name: password
in: query
description: The password for login in clear text
required: true
schema:
type: string
responses:
'200':
description: token
'400':
description: Invalid username or password.
参数传入用户名和密码,验证成功之后,返回JWT
具体实现如下:
class UserLoginHandler : public flare::HttpHandler {
public:
void OnGet(const flare::HttpRequest& request, flare::HttpResponse* response,
flare::HttpServerContext* context) override;
};
void UserLoginHandler::OnGet(const flare::HttpRequest& request,
flare::HttpResponse* response,
flare::HttpServerContext* context) {
ParamParse param_parse(request.uri());
auto username = param_parse.Get("username");
auto password = param_parse.Get("password");
if (!username || !password ||
!UserManager::Instance()->Check(*username, *password)) {
response->set_status(flare::HttpStatus::BadRequest);
return;
}
auto token = TokenUtil::Instance()->GenerateToken(*username);
response->set_body(token);
response->set_status(flare::HttpStatus::OK);
}
Handler接口提供了OnGet、OnPost、OnPut、OnDelete等方法,我们在实现的时候按需实现就好,这里用户登陆使用的是HTTP的GET方法,因此只需要实现一个OnGet方法。
ParamParse是我自己通过正则表达式实现的一个Get方法参数解析器,将参数从uri中抽取出来,检查正确性之后,使用JWT生成工具生成一个属于这个用户的token,并返回,JWT生成方式可以参考之前的jwt-cpp的用法介绍。
ParamParse
ParamParse类中提供了路径参数和get参数两种解析方式:
class ParamParse {
public:
using PathParam = std::vector<std::pair<std::string, std::optional<std::string>>>;
using PathParamMap = std::unordered_map<std::string, std::optional<std::string>>;
ParamParse(const std::string& uri) : _uri(uri) {}
std::optional<std::string> Get(const std::string& key);
/**
* eg. /room/{roomId}/enter
**/
PathParamMap GetPathParam(const std::string& path);
private:
const std::string& _uri;
};
c++的正则表达式其实用起来挺繁琐的,返回值都包在了一个smatch里,在取结果的时候需要熟悉regex库返回值的结构,有空的时候可以详细介绍一下c++的正则表达式库。
小结
今天介绍了如何使用flare搭建一套HTTP服务,实现了用户登陆,但是flare内置的HTTP服务支持较少,因此我自己稍微写了一些HTTP相关的参数解析的程序,这里也展示给大家,将来为大家详细介绍一下ParamParse这个通过正则表达式抽取HTTP参数的短小的类。下面几天,我会带领大家尝试完成用户未登陆的拦截,用户注册等接口,为大家展示flare的HTTP框架及其提供的一些基础库。