2.17从 cURL 命令发送

推荐使用 ReqBin 在线测试和学习 cURL 命令,该网站提供大量可直接运行的 cURL 示例,调试 API 非常方便。

在与第三方 API 对接或调试时,cURL 命令是最常见的请求描述方式。框架内置了 cURL 命令解析引擎,支持从原生 cURL 命令字符串一键发起 HTTP 请求,覆盖常用选项(如 -X-H-d-F-u--data-urlencode--max-time--http2 等),并可自由扩展自定义标志。

使用方式非常简单:将 cURL 命令直接传入 HttpRequestBuilder.FromCurl(),然后通过 IHttpRemoteService 发送即可。

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("curl https://furion.net"));

下面通过多个场景示例展示具体用法。

常规 GET 请求#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("curl https://furion.net"));

携带查询参数和 JSON 请求体#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("""        curl -k -X POST 'https://localhost:7044/HttpRemote/AddModel?query1=10&query2=hello' \        -H 'Content-Type: application/json' \        -d '{          "id": 1,          "name": "sample"        }'        """));

多部分表单(文件上传 + 普通字段)#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("""        curl -k -X POST 'https://localhost:7044/HttpRemote/AddForm?id=100' \        -F 'Id=100' \        -F 'Name=furion' \        -F 'File=@C:\Workspaces\httptest.jpg'        """));

文件上传使用 @ 前缀,路径支持本地绝对路径(如 C:\...)或网络 URL(如 @https://example.com/avatar.png)。

URL 编码表单(application/x-www-form-urlencoded#

使用 -d 发送 URL 编码数据:

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("""        curl -k -X POST 'https://localhost:7044/HttpRemote/AddUrlForm' \        -H 'Content-Type: application/x-www-form-urlencoded' \        -d 'id=200&name=furion'        """));

使用 --data-urlencode 自动编码空格等特殊字符:

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("""        curl -k -X POST 'https://localhost:7044/HttpRemote/AddUrlForm' \        --data-urlencode 'id=200' \        --data-urlencode 'name=fu rion'        """));

单个文件上传#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("""        curl -k -X POST 'https://localhost:7044/HttpRemote/AddFile' \        -F 'file=@C:\Workspaces\httptest.jpg'        """));

多个文件上传#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("""        curl -k -X POST 'https://localhost:7044/HttpRemote/AddFiles' \        -F 'files=@C:\Workspaces\httptest.jpg' \        -F 'files=@C:\Workspaces\httptest.jpg'        """));

发送原始字符串(如 "This is a raw string"#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("""        curl -k -X POST 'https://localhost:7044/HttpRemote/RawString' \        -H 'Content-Type: application/json' \        -d '"This is a raw string"'        """));

带有认证信息的请求#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("""        curl -X POST https://jsonplaceholder.typicode.com/posts \        -H "Content-Type: application/json" \        -u testuser:testpass \        -d '{"title":"Test"}'        """));

忽略输出选项(如 -o#

某些 cURL 选项(如 -o-v-s)属于输出控制,不影响请求构建,会被自动忽略。例如:

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromCurl("curl -o qr.png \"https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=Hello\""));

该命令会正常发送 GET 请求并获取响应内容,但不会将结果保存为文件(文件保存需自行处理)。

扩展自定义 cURL 选项#

框架的 cURL 解析器采用可插拔提取器架构,每个 cURL 选项均由独立的 IHttpCurlExtractor 实现处理。您可以通过新增自定义提取器来支持私有 cURL 标志(如 --my-flag),而无需修改框架源码。

实现自定义提取器#

创建自定义提取器最便捷的方式是继承 HttpCurlExtractorBase 基类,它已封装好游标推进和参数消费逻辑:

cs
/// <summary>///     自定义 --my-flag 提取器/// </summary>internal sealed class CurlMyFlagExtractor : HttpCurlExtractorBase{    /// <summary>    ///     匹配的标志集合(大小写不敏感)    /// </summary>    protected override string[] Flags => ["--my-flag"];    /// <summary>    ///     是否需要参数。默认为 true;如果标志无需参数则设为 false。    /// </summary>    protected override bool RequiresArgument => true;    /// <summary>    ///     当匹配到标志时执行的具体操作    /// </summary>    /// <param name="httpRequestBuilder">请求构建器</param>    /// <param name="flag">当前匹配的标志(已转为小写)</param>    /// <param name="argument">携带的参数值,若无参数则为 null</param>    protected override void Extract(HttpRequestBuilder httpRequestBuilder, string flag, string? argument)    {        // 此处根据标志设置构建器        if (!string.IsNullOrWhiteSpace(argument))        {            // 示例:将参数值放入 X-My-Flag 请求头            httpRequestBuilder.WithHeader("X-My-Flag", argument);        }    }}

对于更复杂的场景(如需要控制优先级、手动管理游标),可直接实现 IHttpCurlExtractor 接口;若需排序,则额外实现 IOrderedHttpCurlExtractor 接口(Order 越小优先级越高)。

注册自定义提取器#

自定义提取器在调用 FromCurl 时通过配置委托注入:

cs
var builder = HttpRequestBuilder.FromCurl(    "curl --my-flag hello-world http://example.com",    options => options.AddExtractor(new CurlMyFlagExtractor()));

如需移除内置提取器,可使用 options.RemoveExtractor<T>()。例如:

cs
var builder = HttpRequestBuilder.FromCurl(    "curl http://example.com",    options => options.RemoveExtractor<CurlHeaderExtractor>());

上下文对象说明#

HttpCurlParsingContext 提供了丰富的游标控制方法:

成员说明
CurrentToken获取当前指向的 Token
PeekNext()预览下一个 Token(不移动指针)
Advance(count)向前推进指定步数(默认 1)
CurrentTokenMatches(flags)检查当前 Token 是否匹配给定标志集合(忽略大小写)
IsEndOfTokens是否已到达 Token 列表末尾

在直接实现 IHttpCurlExtractor 时,您需要自行调用 Advance 来消费 Token,否则会导致解析死循环。

参考实现#

框架内置的所有提取器(如 CurlMethodExtractorCurlFormExtractor 等)均基于相同的接口和基类构建,您可以在仓库中查看其源码作为参考:查看内置提取器源码