Demo:HTTP 请求与 JSON
可构建、可运行、可验证,并与仓库 examples 目录中的源码保持一致。
1. 示例内容
完整源码中的关键调用均有中文注释,页面同时给出运行命令、验证方法和可调整参数。
2. 构建与运行
cmake --build build --target sttnet_http_json --parallel
./build/examples/sttnet_http_json3. 运行结果
curl -i -X POST http://127.0.0.1:8081/json -H "Content-Type: application/json" -d '{"name":"Stephen"}'预期:返回 201 Created 和 JSON 响应。
4. 完整源码
#include <sttnet.h>
#include <iostream>
#include <memory>
#include <string>
int main()
{
using namespace stt::network;
using stt::system::ServerSetting;
// 在 STTNet 创建 Reactor 或 Worker 线程前屏蔽 SIGINT/SIGTERM。
// 这样主线程稍后能在正常 C++ 上下文中清理资源。
if(!ServerSetting::blockTerminationSignals())
{
std::cerr << "failed to block termination signals\n";
return 1;
}
HttpServer server;
// GET /inspect 展示如何读取 STTNet 已解析的 HTTP 请求。
server.setFunction("/inspect",
[](HttpServerFDHandler &client, HttpRequestInformation &request) {
// headerValue() 不区分大小写,并返回非拥有视图。
// 跨回调保存时复制为拥有数据的字符串。
const std::string contentType(request.headerValue("content-type"));
// bodyView() 同时支持 Content-Length 和 chunked 请求体。
const std::string body(request.bodyView());
Json::Value response;
response["ok"] = true;
response["method"] = request.type;
response["path"] = request.loc;
response["query"] = request.para;
response["content_type"] = contentType;
response["body"] = body;
// 发送成功表示响应已进入 STTNet 的
// 有界发送队列;发送失败时返回 -2 请求关闭连接。
return client.sendJson(response) ? 1 : -2;
});
// POST /json 解析客户端 JSON 请求体并校验字段。
server.setFunction("/json",
[](HttpServerFDHandler &client, HttpRequestInformation &request) {
if(request.type != "POST")
{
Json::Value error;
error["ok"] = false;
error["error"] = "POST required";
return client.sendJson(error, "405 Method Not Allowed",
"Allow: POST\r\n") ? 1 : -2;
}
// JsonCpp 的 CharReader 会返回语法错误而不是抛异常。
const std::string body(request.bodyView());
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::Value input;
std::string parseError;
if(!reader->parse(body.data(), body.data() + body.size(),
&input, &parseError))
{
Json::Value error;
error["ok"] = false;
error["error"] = "invalid JSON";
error["detail"] = parseError;
return client.sendJson(error, "400 Bad Request") ? 1 : -2;
}
if(!input.isMember("name") || !input["name"].isString() ||
input["name"].asString().empty())
{
Json::Value error;
error["ok"] = false;
error["error"] = "field 'name' must be a non-empty string";
return client.sendJson(error, "422 Unprocessable Entity") ? 1 : -2;
}
Json::Value response;
response["ok"] = true;
response["message"] = "hello, " + input["name"].asString();
return client.sendJson(response, "201 Created") ? 1 : -2;
});
// 全局回调负责处理没有注册路由的路径。
server.setGlobalSolveFunction(
[](HttpServerFDHandler &client, HttpRequestInformation &) {
Json::Value error;
error["ok"] = false;
error["error"] = "route not found";
return client.sendJson(error, "404 Not Found") ? 1 : -2;
});
if(!server.startListen(8081))
{
std::cerr << "failed to listen on port 8081\n";
return 2;
}
std::cout << "HTTP/JSON demo listening on http://127.0.0.1:8081\n";
ServerSetting::waitForTerminationSignal();
return server.close() ? 0 : 3;
}