ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

cpp-httplib 自定义 HTTP 方法实战:用 CustomRoute() 支持 WebDAV、UPnP 等扩展方法

cpp-httplib 自定义 HTTP 方法实战:用 CustomRoute() 支持 WebDAV、UPnP 等扩展方法 后端网络【免费下载链接】cpp-httplibA C header-only HTTP/HTTPS server and client library项目地址https://gitcode.com/GitHub_Trending/cp/cpp-httplib点击查看免费下载本篇技术指南以 cpp-httplib 的CustomRoute()API 为核心讲解如何在默认只接受标准 HTTP 方法的服务器上注册并路由PROPFIND、PROPPATCH、MKCOL、REPORT、SUBSCRIBE等扩展方法并配合OPTIONS能力通告实现可用的 WebDAV / UPnP 服务。读完本文你将掌握自定义方法的注册写法、内容读取器Content Reader流式处理请求体、注册校验与启动失败的联动机制以及对应的源码级实现依据。为什么需要自定义 HTTP 方法HTTP 协议RFC 9110定义了GET、HEAD、POST、PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH等方法但现实世界中的许多协议会在其上扩展新方法WebDAVRFC 4918PROPFIND、PROPPATCH、MKCOL、COPY、MOVE、LOCK、UNLOCK等用于文件与目录的分布式管理UPnPSUBSCRIBE/NOTIFY等用于事件订阅与推送其他扩展REPORTWebDAV 的搜索与版本控制扩展、M-SEARCHSSDP等。cpp-httplib 的默认行为是服务器对不认识的 HTTP 方法直接以400 Bad Request拒绝。这一拦截发生在请求行解析阶段——httplib.h 中parse_request_line()的逻辑是当方法不在内置方法集合builtin_methods()中、同时也没有通过CustomRoute()注册对应处理器时立即输出Error::InvalidHTTPMethod错误日志并返回 false// httplib.h const auto methods builtin_methods(); if (methods.find(req.method) methods.end() !find_custom_entry(req.method)) { output_error_log(Error::InvalidHTTPMethod, req); return false; }因此注册了处理器本身就是接受该方法的唯一开关——这是理解CustomRoute()语义的关键注册即放行不注册即拒绝。CustomRoute() 基本用法调用Server::CustomRoute(method, pattern, handler)即可为扩展方法注册路由。方法名、URL 模式的写法与Get()等内置方法完全一致正则表达式和路径参数path parameters都可以直接使用svr.CustomRoute(PROPFIND, /dav/:id, [](const httplib::Request req, httplib::Response res) { // 请求体与普通方法一样可以直接读取 auto id req.path_params.at(id); res.status httplib::StatusCode::MultiStatus_207; res.set_content(build_multistatus(req.body), application/xml); });这段代码演示了三个关键点模式匹配复用同一套机制/dav/:id中的:id路径参数会被解析进req.path_params与Get(/dav/:id, ...)的行为完全一致正则表达式模式如/dav/.*同样可用请求体按需读取req.body中已经装载了完整请求体和Post()处理器中的用法没有差别自定义状态码httplib::StatusCode::MultiStatus_207对应 WebDAV 的207 Multi-Status用于返回集合操作的部分成功结果。从源码看CustomRoute()存在两个重载签名分别是Handler与HandlerWithContentReader见 httplib.h前者把处理器挂到custom_handlers_表后者挂到handlers_for_content_reader表对应下文流式读取的用法inline Server Server::CustomRoute(const std::string method, const std::string pattern, Handler handler); inline Server Server::CustomRoute(const std::string method, const std::string pattern, HandlerWithContentReader handler);注册校验机制从 is_token 到 is_valid()并非任何字符串都能作为方法名注册。CustomRoute()在真正插入路由表之前会经过custom_entry_for_registration()的严格校验见 httplib.hif (!detail::fields::is_token(method) || builtin_methods().count(method)) { output_error_log(Error::InvalidHTTPMethod, nullptr); has_invalid_registration_ true; return nullptr; }方法名必须是合法的 HTTP TokenRFC 9110is_token()要求方法名非空且每个字符都落在 token 字符集内。具体的判定实现在 httplib.h字母数字以及! # $ % * - . ^ _| ~等特殊字符被允许空格、制表符、斜杠、逗号、冒号、括号、控制字符如\x01都会导致校验失败。内置方法禁止注册builtin_methods()见 httplib.h维护了一个 10 元素集合GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH, PRI这些方法被排除在CustomRoute()之外的原因在源码注释中解释得很清楚GET、HEAD、POST、PUT、DELETE、OPTIONS、PATCH由routing()中的 if/else 分发链先行处理注册到自定义表也永远不会被触发CONNECT隧道建立、TRACE请求回显、PRIHTTP/2 连接前导承载着协议级语义库本身不做路由。因此这些方法必须使用专用的Get()、Post()、Put()、Options()等 API 注册而不是塞进CustomRoute()。拒绝注册的后果is_valid() 与 listen() 联动一旦某个注册被拒绝has_invalid_registration_标志位会被置位该标志在listen()前写入、由同一线程的is_valid()读取无需同步。此后svr.is_valid()返回falselisten()调用失败返回false。这套机制保证了服务器绝不会带着一个永远无法触发的处理器启动。更值得注意的是粘性行为拒绝状态不会被后续的合法注册清除。在 test/test.cc 的RejectionIsSticky测试中依次注册PROPFIND合法、GET非法、MKCOL合法后is_valid()仍然为false——也就是说一次非法注册就足以让整个服务器拒绝启动注册顺序、后续合法注册都无法挽回。测试 test/test.cc 完整覆盖了这套校验矩阵测试用例验证内容RejectsBuiltInMethods10 个内置方法逐个注册均被拒绝且is_valid()、listen()均为 falseRejectsNonTokenMethods空字符串、PRO PFIND、含\t/,:(及控制字符的名称均被拒绝AcceptsWebDavAndUpnpMethodsPROPFIND、PROPPATCH、MKCOL、COPY、MOVE、LOCK、UNLOCK、REPORT、SUBSCRIBE均可注册成功ContentReaderOverloadRejectsBuiltInMethodsContent Reader 重载同样拒绝内置方法ReportsRejectionToErrorLogger拒绝时通过set_error_logger()回调收到Error::InvalidHTTPMethod用 OPTIONS 通告服务器能力WebDAV 客户端在发起任何操作之前会先发送OPTIONS请求探测服务器能力。cpp-httplib 不会自动生成DAV:头或Allow头这两者必须由你自己返回。如果遗漏这一步即使PROPFIND处理器工作正常客户端也会因能力通告缺失而拒绝继续交互。svr.Options(/dav/.*, [](const httplib::Request req, httplib::Response res) { res.set_header(DAV, 1); res.set_header(Allow, OPTIONS, GET, HEAD, PROPFIND, PROPPATCH, MKCOL); });DAV: 1表明服务器支持 WebDAVRFC 4918的 class 1 能力Allow头列出服务器实际接受的完整方法清单需要与你在代码中注册的方法保持一致客户端会据此决定后续行为。注意这里使用的是svr.Options(...)内置方法专用 API而不是CustomRoute(OPTIONS, ...)——因为OPTIONS属于内置方法无法通过CustomRoute()注册。用 Content Reader 流式读取请求体大型 WebDAV 请求例如PROPFIND携带深目录请求、REPORT携带查询表达式可能包含体积可观的 XML。如果不想一次性把整个请求体载入内存可以使用CustomRoute()的Content Reader 重载用法与Post()的 Content Reader 版一致svr.CustomRoute(REPORT, /dav/.*, [](const httplib::Request req, httplib::Response res, const httplib::ContentReader content_reader) { content_reader( { // 逐块处理请求体数据 return true; // 返回 false 可中止读取 }); res.status httplib::StatusCode::MultiStatus_207; });content_reader接受一个接收回调框架会分块回调(data, data_length)处理器在回调内逐步消费数据回调返回false可提前终止读取。一个容易被忽略的实现细节值得展开Content Reader 路由在请求完全没有请求体时也会触发。routing()中的判定条件见 httplib.h是if (detail::expect_content(req) || (custom !custom-handlers_for_content_reader.empty())) {也就是说只要某个自定义方法注册了 Content Reader 处理器即使请求头既没有Content-Length也没有Transfer-Encoding该处理器仍然会被调用。这对 WebDAV 有实际意义RFC 4918 规定不带请求体的PROPFIND等价于allprop请求返回全部属性。如果缺少这一逻辑body-less 的PROPFIND会跳过处理器直接落到 404。对应地test/test.cc 的CustomMethodWithoutFraming测试专门验证了发送不带任何 framing 信息的裸PROPFIND /dav请求服务器应立即返回207 Multi-Status而不是阻塞在等待 EOF 的读取上。静态文件与 WebSocket仍只走 GET / HEAD自定义方法只影响 HTTP 方法路由不影响其他子系统静态文件服务set_mount_point()/set_base_dir()挂载的静态文件仍只响应GET和HEAD见 httplib.h 中routing()的文件处理分支if ((req.method GET || req.method HEAD) handle_file_request(req, res))WebSocket 升级同样以GET为基础握手流程。如果需要 WebDAV 风格的虚拟文件系统把PROPFIND映射到静态目录之外的业务逻辑由你自己实现库只负责路由分发。边界与责任库只路由不实现协议最后需要明确 cpp-httplib 的能力边界CustomRoute()提供的仅仅是方法级别的路由。如果你的服务要自称 WebDAV 实现那么协议本体——207 Multi-Status响应 XML 的生成、Depth头的语义解释、Lock-Token/If头的锁管理、DAV:属性文档——全部需要你自己实现。此外方法名必须是合法的 HTTP tokenRFC 9110且必须在listen()之前完成注册GET、HEAD、POST、PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH、PRI这 10 个内置方法不可通过CustomRoute()注册请使用对应的专用方法被拒绝的注册会让is_valid()返回false、listen()失败且该拒绝状态是粘性的服务器绝不会带着永远无法触发的手柄启动。延伸阅读处理器注册的基础知识路径匹配、正则、路径参数、Content Reader 语义参见 S01. GET / POST / PUT / DELETE 处理器注册入门自定义方法的完整实现与校验逻辑见 httplib.hbuiltin_methods()/custom_entry_for_registration()/CustomRoute()/find_custom_entry()以及 httplib.h 的请求行校验路由分发与 Content Reader 分支见 httplib.h全部注册校验与无 framing 请求的测试用例集中在 test/test.cc。赞分享后端网络【免费下载链接】cpp-httplibA C header-only HTTP/HTTPS server and client library项目地址https://gitcode.com/GitHub_Trending/cp/cpp-httplib点击查看免费下载相关推荐cpp-httplib 自定义 HTTP 方法用 CustomRoute() 接入 WebDAV、UPnP 等扩展协议cpp httplib 自定义 HTTP 方法用 CustomRoute 接入 WebDAV、UPnP 等扩展协议 导读 cpp httplib 默认只识别后端网络在 Chromium 中使用 VSCode rust-analyzergn 导出 Rust 项目与 IDE 开发指南在 Chromium 中使用 VSCode rust analyzergn 导出 Rust 项目与 IDE 开发指南 Rust 代码中大量类型信息会被编译文档教程requests 怎么发送 MKCOL 等自定义 HTTP 动词使用 request() 方法对接 WebDAV 服务requests 怎么发送 MKCOL 等自定义 HTTP 动词使用 request 方法对接 WebDAV 服务 对接 WebDAV 类服务时经常会用到后端网络通信创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表