2.18从 JSON 发送

框架同样支持从 JSON 配置字符串一键发起 HTTP 请求,完全替代传统的链式调用。只需将请求参数组织为 JSON 格式,传入 HttpRequestBuilder.FromJson() 方,然后通过 IHttpRemoteService 发送即可。

框架同样支持从 JSON 配置字符串一键发起 HTTP 请求,完全替代传统的链式调用。只需将请求参数组织为 JSON 格式,传入 HttpRequestBuilder.FromJson() 方,然后通过 IHttpRemoteService 发送即可。

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://furion.net",            "method": "GET"        }        """));

JSON 语法全览#

下表列出了所有可用的 JSON 字段(属性名不区分大小写,且支持尾随逗号):

字段 (主键)别名 (Aliases)类型必填说明
methodstring请求方式(GETPOSTPUTDELETEPATCH 等)。若未指定,则根据是否包含请求体自动推断:有请求体时为 POST,否则为 GET
urlrequestUristring请求地址。支持绝对 URI(如 https://api.example.com)或相对路径(如 /api/data)。相对路径可配合 baseURL 使用。
baseURLbaseAddress, baseUrlstring请求基地址。必须为绝对 URI。当 url 为相对路径时,两者将按规则拼接为完整地址。
headersobject请求标头字典。键为标头名称,值为标头值(字符串)。例如 {"Accept": "application/json", "X-API-Key": "xxx"}
paramsqueries, query, queryParametersobjectURL 查询参数。将自动拼接到请求地址的 ? 后面。例如 {"page": 1, "size": 10}?page=1&size=10
cookiesobjectCookies 字典。例如 {"session": "abc", "user": "john"}
timeoutnumber超时时间(毫秒)。例如 5000 表示 5 秒。
clientclientName, httpClientNamestringIHttpClientFactory 中注册的客户端名称。用于选择特定的 HttpClient 实例。
httpVersionversionstringHTTP 版本。支持 "1.0""1.1""2.0""3.0" 等。
authauthentication, authorizationobject身份认证配置。必须包含 type 字段("bearer""basic""digest")。
Bearer 示例{"type": "bearer", "token": "xxx"},可选 "header" 自定义标头名(默认 Authorization)。
Basic 示例{"type": "basic", "username": "user", "password": "pass"}
Digest 示例{"type": "digest", "username": "user", "password": "secret"}
dataany请求体内容。可以是 JSON 对象、字符串、数字等。框架会将 JsonNode 作为原始内容传递,最终由内容处理器推断 Content-Type
contentTypestring配合 data 使用,显式指定 Content-Type。若不指定,框架会根据 data 的实际类型自动推断(例如 JSON 对象推断为 application/json)。
encodingstring配合 data 使用,指定内容编码(如 "utf-8")。若未指定,使用默认编码。
multipartobject多部分表单(multipart/form-data)内容。对象的每个属性代表一个表单项。
普通字段:"name": "John" → 文本字段。
文件字段:"file": "@C:\\path\\to\\file.jpg""@https://example.com/file.png"(网络文件)。
支持 @file;type=mime/type@file;filename=renamed.txt 语法。
多文件上传:"files": ["@file1.jpg", "@file2.jpg"](数组形式,同一字段名)。
profilerdebuggerboolean是否启用请求分析工具。true 启用,false 禁用。

注意:当未指定 method 时,框架根据 datamultipart 是否存在自动推断:存在则为 POST,否则为 GET

常规 GET 请求#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://furion.net",            "method": "GET"        }        """));

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

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://localhost:7044/HttpRemote/AddModel",            "method": "POST",            "queries": {                "query1": 10,                "query2": "hello"            },            "headers": {                "Content-Type": "application/json"            },            "data": {                "id": 1,                "name": "sample"            }        }        """));

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

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://localhost:7044/HttpRemote/AddForm",            "method": "POST",            "queries": {                "id": 100            },            "multipart": {                "Id": 100,                "Name": "furion",                "File": "@C:\\Workspaces\\httptest.jpg"            }        }        """));

文件字段值以 @ 开头,支持本地绝对路径或网络 URL(如 "@https://example.com/avatar.png")。同时支持 @path;type=image/png@path;filename=photo.jpg 等扩展语法。

URL 编码表单#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://localhost:7044/HttpRemote/AddUrlForm",            "method": "POST",            "headers": {                "Content-Type": "application/x-www-form-urlencoded"            },            "data": "id=200&name=furion"        }        """));

或者通过对象自动序列化(需显式指定 contentType):

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://localhost:7044/HttpRemote/AddUrlForm",            "method": "POST",            "data": {                "id": 200,                "name": "fu rion"            },            "contentType": "application/x-www-form-urlencoded"        }        """));

单个文件上传#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://localhost:7044/HttpRemote/AddFile",            "method": "POST",            "multipart": {                "file": "@C:\\Workspaces\\httptest.jpg"            }        }        """));

多个文件上传#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://localhost:7044/HttpRemote/AddFiles",            "method": "POST",            "multipart": {                "files": ["@C:\\Workspaces\\file1.jpg", "@C:\\Workspaces\\file2.jpg"]            }        }        """));

发送原始字符串#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://localhost:7044/HttpRemote/RawString",            "method": "POST",            "headers": {                "Content-Type": "application/json"            },            "data": "\"This is a raw string\""        }        """));

带有认证信息的请求#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://jsonplaceholder.typicode.com/posts",            "method": "POST",            "headers": {                "Content-Type": "application/json"            },            "auth": {                "type": "basic",                "username": "testuser",                "password": "testpass"            },            "data": {                "title": "Test"            }        }        """));

指定超时和 HTTP 版本#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://httpbin.org/delay/3",            "method": "GET",            "timeout": 5000,            "httpVersion": "2.0"        }        """));

启用请求分析工具#

cs
var result = await httpRemoteService.SendAsStringAsync(    HttpRequestBuilder.FromJson("""        {            "url": "https://furion.net",            "method": "GET",            "profiler": true        }        """));

扩展自定义 JSON 提取器#

cURL 解析器类似,JSON 解析也采用可插拔提取器架构。每个 JSON 字段由一个 IHttpJsonExtractor 实现处理。您可以新增自定义提取器来支持私有字段(如 "customField"),而无需修改框架源码。

实现自定义提取器#

最便捷的方式是继承 HttpJsonExtractorBase 抽象基类,它已封装好属性名与别名匹配逻辑:

cs
using HttpAgent;/// <summary>///     自定义 json.customField 提取器/// </summary>internal sealed class JsonCustomFieldExtractor : HttpJsonExtractorBase{    /// <summary>    ///     主属性名    /// </summary>    protected override string PropertyName => "customField";    /// <summary>    ///     可选别名列表    /// </summary>    protected override string[]? Aliases => ["custom", "custom_field"];    /// <summary>    ///     当匹配到属性时执行的具体操作    /// </summary>    protected override void Extract(HttpRequestBuilder httpRequestBuilder, JsonNode node,        HttpJsonParsingContext context)    {        // 此处根据节点值设置构建器        if (node is JsonValue jsonValue && jsonValue.TryGetValue<string>(out var value))        {            httpRequestBuilder.WithHeader("X-Custom-Field", value);        }    }}

对于更复杂的场景,可直接实现 IHttpJsonExtractor 接口,手动遍历根 JsonObject

注册自定义提取器#

在调用 FromJson 时通过配置委托注入:

cs
var builder = HttpRequestBuilder.FromJson("""    {        "url":"http://example.com",        "method":"GET",        "customField":"hello"    }    """,    options => options.AddExtractor(new JsonCustomFieldExtractor()));

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

cs
var builder = HttpRequestBuilder.FromJson("""    {        "url":"http://example.com"    }    """,    options => options.RemoveExtractor<JsonMethodExtractor>());

上下文对象说明#

HttpJsonParsingContext 提供了对根 JsonObject 的安全访问方法:

成员说明
RootObject获取根 JsonObject
TryGetNode(propertyName, out node)安全获取指定属性名的 JsonNode,不存在时返回 false
GetNode(propertyName)获取指定属性名的 JsonNode,不存在时返回 null
ContainsProperty(propertyName)检查根对象是否包含指定属性

参考实现#

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