- 后端
- API设计
【免费下载链接】RestSharp
Simple REST and HTTP API Client for .NET
导读
本文以 RestSharp v1.13 官方文档 usage/request.md 为骨架,系统讲解如何构建一个RestRequest实例:包括创建请求、添加各类参数(Header、GetOrPost、QueryString、UrlSegment、Cookie)、使用AddObject/AddObjectStatic批量映射对象属性、构造 JSON / XML / 字符串请求体以及上传文件等完整流程。读完本文,你将掌握 RestSharp 请求构建的每一种参数类型的语义、行为差异与底层实现,能够直接编写可运行的 REST 客户端代码。
创建请求:从 resource 到 Method
RestSharp 中所有请求都围绕RestRequest展开。使用RestClient发起请求之前,必须先创建一个请求实例:
var request = new RestRequest(resource); // resource 是相对于客户端 BaseUrl 的子路径resource是客户端基础地址的子路径。从源码可见,RestRequest的默认构造函数将方法设为Method.Get(见 RestRequest.cs),因此默认请求类型是 GET。你可以通过设置Method属性覆盖,也可以直接用构造函数重载指定:
var request = new RestRequest(resource, Method.Post);构造函数签名对应源码中的RestRequest(string? resource, Method method = Method.Get)(见 RestRequest.cs)。此外还有接受Uri的重载:若传入绝对 URI,则以AbsoluteUri作为 resource;若为相对 URI,则取其OriginalString(见 RestRequest.cs)。
一个值得注意的细节:当resource字符串中带有查询串(如search?foo=bar)时,构造函数会自动解析该查询串并转换为QueryParameter加入请求,同时把Resource还原为不含查询串的部分(见 RestRequest.cs)。
请求创建后,就可以向它添加各类参数。RestSharp 支持的参数类型与用途如下表:
| 参数类型 | 添加方式 | 作用位置 | 说明 |
|---|---|---|---|
| HeaderParameter | AddHeader | HTTP 头 | 随请求发送的请求头 |
| GetOrPostParameter | AddParameter | URL 或请求体 | 按 HTTP 方法决定去向 |
| QueryParameter | AddQueryParameter | URL 查询串 | 始终追加到 URL |
| UrlSegmentParameter | AddUrlSegment | URL 路径占位符 | 替换{placeholder} |
| Cookie | AddCookie | Cookie 头 | 请求级 Cookie |
| BodyParameter / JsonParameter / XmlParameter | AddJsonBody/AddXmlBody/AddStringBody/AddBody | 请求体 | 请求正文 |
Request headers:请求头
Header 参数以参数名为头名、参数值为头值,作为 HTTP 头随请求发送。常用的添加方法有三个:
AddHeader(string name, string value); AddHeader<T>(string name, T value); // value 会被转换为字符串 AddOrUpdateHeader(string name, string value); // 已存在同名头时直接替换用法示例:
var request = new RestRequest("/path").AddHeader("X-Key", someKey);从源码看,AddHeader(string, string)内部创建HeaderParameter(见 RestRequestExtensions.Headers.cs),AddOrUpdateHeader则通过AddOrUpdateParameter替换同名已有参数(见 RestRequestExtensions.Headers.cs)。泛型重载AddHeader<T>要求T : struct,值会按指定的 culture(默认InvariantCulture)格式化为字符串(见 RestRequestExtensions.Headers.cs)。若需要批量添加,还有AddHeaders/AddOrUpdateHeaders,它们会先检查是否存在重复键(大小写不敏感),有重复则抛出ArgumentException(见 RestRequestExtensions.Headers.cs)。
RestSharp 在调用资源时会自动区分请求头与内容头(content headers)。你也可以把 Header 参数加在客户端上,这样每次请求都会带上——非常适合鉴权头等公共头:
client.AddDefaultHeader(string name, string value);源码中AddDefaultHeader实现在 RestClient.Extensions.Params.cs,它同样以HeaderParameter加入客户端默认参数集合。
:::warning 避免手动设置 Content-Type 头 RestSharp 默认会使用正确的内容类型。除非你非常确定需要,否则不要手动给请求添加Content-Type头;如需自定义内容类型,请直接设置到 body 参数 本身。 :::
Get or Post parameters:默认参数类型
GetOrPostParameter是 RestSharp 的默认参数类型,通过AddParameter添加:
request .AddParameter("name1", "value1") .AddParameter("name2", "value2");GetOrPost的行为随 HTTP 方法而变化:
- GET 请求:参数追加到 URL,形如
url?name1=value1&name2=value2; - POST / PUT 请求:取决于请求是否携带文件:
- 无文件时,参数以
name1=value1&name2=value2的形式作为请求体发送,Content-Type 为application/x-www-form-urlencoded; - 有文件时,发送
multipart/form-data请求,每个参数以如下形式出现在 multipart 中:
- 无文件时,参数以
Content-Type: text/plain; charset=utf-8 Content-Disposition: form-data; name="parameterName" ParameterValue两种情况下,参数名与参数值默认都会被 URL 编码,除非显式指定不编码:
request.AddParameter("name", "Væ üé", false); // 不编码 value在 multipart 表单调用中,有时需要覆盖参数默认的内容类型,可通过设置参数对象的ContentType属性实现。下面的代码创建一个值为 JSON 的 POST 参数,并指定适当的内容类型:
var parameter = new GetOrPostParameter("someJson", "{\"attributeFormat\":\"pdf\"}") { ContentType = "application/json" }; request.AddParameter(parameter);当请求使用 multipart 内容时,该参数将携带指定内容类型发送:
Content-Type: application/json; charset=utf-8 Content-Disposition: form-data; name="someJson" {"attributeFormat":"pdf"}GetOrPost参数同样可以注册为客户端默认参数,从而附加到该客户端发起的每个请求:
client.AddDefaultParameter("foo", "bar");其行为与请求级参数完全一致,只是作用于全部请求。
Query string:查询串参数
QueryString与GetOrPost类似,但无论请求方法是什么,始终把参数以url?name1=value1&name2=value2形式追加到 URL。示例:
var client = new RestClient("https://search.me"); var request = new RestRequest("search") .AddParameter("foo", "bar"); var response = await client.GetAsync<SearchResponse>(request);该代码会向https://search.me/search?foo=bar发送 GET 请求。对于 POST 风格的请求,则需要显式添加查询串参数:
request.AddQueryParameter("foo", "bar");AddQueryParameter内部创建QueryParameter,encode参数默认为true(见 RestRequestExtensions.Query.cs)。有时需要禁止 RestSharp 对查询串参数编码,将encode参数设为false即可:
request.AddQueryParameter("foo", "bar/fox", false);与前述类型一致,查询串参数也可注册为客户端默认参数:
client.AddDefaultQueryParameter("foo", "bar");上面这行代码会使该客户端实例发起的所有请求都在查询串中携带foo=bar。其底层实现在 RestClient.Extensions.Params.cs,以QueryParameter形式加入默认参数集合。
Using AddObject:把对象属性批量映射为参数
如果你有一组参数需要一次性添加,可以先把它们收集进一个对象,再调用AddObject:
var params = new { status = 1, priority = "high", ids = new [] { "123", "456" } }; request.AddObject(params);它等价于:
request.AddParameter("status", 1); request.AddParameter("priority", "high"); request.AddParameter("ids", "123,456");注意,AddObject只支持基本类型(primitive)属性,也支持如上所示的基本类型集合。从源码看,AddObject通过反射获取对象属性,然后逐个调用AddParameter(prop.Name, prop.Value, prop.Encode)(见 RestRequestExtensions.Object.cs)。它还有可选参数includedProperties,用于指定只提取哪些属性。
如果需要覆盖属性名或格式,可以使用RequestProperty特性:
public class RequestModel { // 覆盖名称与格式 [RequestProperty(Name = "from_date", Format = "d")] public DateTime FromDate { get; set; } } // 添加到请求 request.AddObject(new RequestModel { FromDate = DateTime.Now });此时请求会得到一个名为from_date的 GET 或 POST 参数,值为当前日期的短日期格式。RequestPropertyAttribute定义在 ObjectParser.cs,支持Name(重命名)、Format(DateTime/数值格式化字符串)、ArrayQueryType(数组序列化方式,默认CommaSeparated,可设为ArrayParameters以生成name[]形式)、Encode(是否编码,默认true)四个属性。
Using AddObjectStatic:预编译表达式的高性能版本
AddObjectStatic<T>(...)使用预编译表达式来获取属性值,与每次调用都走反射的AddObject相比,它会把“从类型T的对象中取属性”的函数缓存起来,因此快得多。
AddObjectStatic支持自定义参数名与格式,也支持传入属性名单,指定哪些属性需要作为参数——当类型T含有不需要随 HTTP 调用发送的属性时,这一选项非常有用。其核心实现依赖PropertyCache<T>:在 RestRequestExtensions.Object.cs 中调用PropertyCache<T>.GetParameters(obj, includedProperties),而PropertyCache.Populator使用System.Linq.Expressions将属性 getter 编译为Func<T, object>委托并缓存(见 PropertyCache.Populator.cs),同时根据属性类型(IFormattable、IConvertible、IEnumerable等)选择不同的转换与序列化路径(CSV 拼接或数组参数)。
使用自定义参数名或格式时同样借助RequestProperty特性。示例:
class TestObject { [RequestProperty(Name = "some_data")] public string SomeData { get; set; } [RequestProperty(Format = "d")] public DateTime SomeDate { get; set; } [RequestProperty(Name = "dates", Format = "d")] public DateTime[] DatesArray { get; set; } public int Plain { get; set; } public DateTime[] PlainArray { get; set; } }URL segment parameter:路径占位符替换
与GetOrPost不同,URL segment 参数用于替换请求 URL 中的占位符:
var request = new RestRequest("health/{entity}/status") .AddUrlSegment("entity", "s2");请求执行时,RestSharp 会把 URL 中的任何{placeholder}与同名(不含{})参数匹配并替换为参数值,因此上面的代码最终请求 URL 为health/s2/status。
从源码看,AddUrlSegment创建UrlSegmentParameter,并通过AddOrUpdateParameter添加(同名占位符可覆盖),encode默认true(见 RestRequestExtensions.Url.cs)。泛型重载AddUrlSegment<T>同样支持指定 culture 格式化值(见 RestRequestExtensions.Url.cs)。
URL segment 参数同样可以作为客户端默认参数添加:
client.AddDefaultUrlSegment("foo", "bar");底层实现在 RestClient.Extensions.Params.cs,会为客户端所有请求的 URL 占位符填充该值。
Cookies:请求级与客户端级 Cookie
使用AddCookie方法即可向请求添加 Cookie:
request.AddCookie("foo", "bar");两个参数的形式会把域解析推迟到执行时刻——Cookie 域从请求 URL 推断。如果需要显式指定路径和域,使用四个参数的重载:
request.AddCookie("foo", "bar", "/path", "example.com");RestSharp 会把请求中的 Cookie 作为 Cookie 头发送,然后从响应中提取匹配的 Cookie。你可以通过RestResponse.Cookies属性(类型为CookieCollection)观察和提取响应 Cookie(见 RestResponseBase.cs)。
在请求级别存在一个CookieContainer实例。你可以把预先填充好的容器赋给request.CookieContainer,也可以让容器在执行时自动创建。四参数AddCookie重载会立即填充容器,而两参数形式先把 Cookie 存入PendingCookies列表(见 RestRequest.cs),直到请求执行时才解析。执行时,RestSharp 会从容器中取出全部 Cookie 生成 Cookie 头,而不是直接使用容器本身——因为 Cookie 容器通常配置在HttpClientHandler级别,同一客户端发起的多个请求之间会共享 Cookie,这在多数场景下是有害的。
如果你的用例确实需要在客户端实例的各请求之间共享 Cookie,可以使用客户端级别的CookieContainer,它必须通过 options 属性提供。你可以使用容器 API 向其中添加 Cookie,但响应 Cookie 不会自动加入容器;需要时可以在代码中从响应的Cookies属性取出,再手动添加到通过IRestClient.Options.CookieContainer属性访问的客户端级容器。
Request Body 请求体
RestSharp 支持多种添加请求体的方式:
AddJsonBody—— JSON 负载AddXmlBody—— XML 负载AddStringBody—— 预序列化负载
官方推荐使用AddJsonBody或AddXmlBody,而不是带BodyParameter的AddParameter——前两者会设置正确的请求类型并替你完成序列化工作。
当发起POST、PUT或PATCH请求并添加了GetOrPost参数时,RestSharp 默认会把它们作为 URL 编码的表单请求体发送;当请求同时有文件时,则发送multipart/form-data请求。你也可以通过把AlwaysMultipartFormData属性设为true强制 RestSharp 以multipart/form-data发送请求体(对应源码属性定义见 RestRequest.cs)。
如有需要,可以指定自定义的请求体内容类型——contentType参数在所有添加请求体的重载中均可使用。
注意:无法添加客户端级别的默认请求体参数。
String body:字符串请求体
如果你有预序列化的负载(例如一段 JSON 字符串),可以用AddStringBody将其作为请求体参数添加。必须指定内容类型,以便远端端点知道如何处理请求体。例如:
const json = "{ \"data\": { \"foo\": \"bar\" } }"; request.AddStringBody(json, ContentType.Json);AddStringBody(string, ContentType)直接创建BodyParameter(见 RestRequestExtensions.Body.cs),还有接受DataFormat的重载会由ContentType.FromDataFormat推导内容类型(见 RestRequestExtensions.Body.cs)。
JSON body:JSON 请求体
调用AddJsonBody时,RestSharp 会为你完成以下工作:
- 指示 RestClient 在发起请求时把对象参数序列化为 JSON;
- 将内容类型设置为
application/json; - 将请求体的内部数据类型设置为
DataType.Json。
示例:
var param = new MyClass { IntData = 1, StringData = "test123" }; request.AddJsonBody(param);可以通过contentType参数覆盖默认内容类型:
request.AddJsonBody(param, "text/x-json");如果向AddJsonBody传入预序列化的字符串,它会原样发送。AddJsonBody会检测参数是否为字符串,若是则作为带 JSON 内容类型的字符串请求体添加。本质上这意味着:使用AddJsonBody时,顶层字符串不会被序列化为 JSON。要解决此问题,可以使用带forceSerialize参数的AddJsonBody重载,强制把字符串序列化为 JSON:
const string payload = @" ""requestBody"": { ""content"": { ""application/json"": { ""schema"": { ""type"": ""string"" } } } },"; request.AddJsonBody(payload, forceSerialize: true); // 字符串会被序列化 request.AddJsonBody(payload); // 字符串不会被序列化,原样发送从源码可以看到这一分支逻辑:AddJsonBody<T>(T obj, ...)中若obj is string str则走AddStringBody(str, DataFormat.Json),否则创建JsonParameter(见 RestRequestExtensions.Body.cs);而带forceSerialize的重载在forceSerialize: true时直接创建JsonParameter(见 RestRequestExtensions.Body.cs)。
XML body:XML 请求体
调用AddXmlBody时,RestSharp 会为你完成以下工作:
- 指示 RestClient 在发起请求时把对象参数序列化为 XML;
- 将内容类型设置为
application/xml; - 将请求体的内部数据类型设置为
DataType.Xml。
源码实现在 RestRequestExtensions.Body.cs,其中AddXmlBody<T>还接受可选参数xmlNamespace用于指定 XML 命名空间。
:::warning 不要把 XML 字符串传给AddXmlBody,那样不会生效! :::
Uploading files:上传文件
使用RestRequest的AddFile函数即可向请求添加文件。主函数接受FileParameter参数:
request.AddFile(fileParameter);你可以用FileParameter.Create(接受字节数组)或FileParameter.FromFile(从磁盘加载文件)实例化文件参数(见 FileParameter.cs)。FromFile会校验文件是否存在,不存在时抛出FileNotFoundException;Create的字节数组重载内部把字节写入MemoryStream再返回流。
还有多个封装了FileParameter创建的扩展函数:
// 从磁盘添加文件 AddFile(parameterName, filePath, contentType); // 添加字节数组 AddFile(parameterName, bytes, fileName, contentType); // 添加 getFile 函数返回的流 AddFile(parameterName, getFile, fileName, contentType);这三个重载的签名与源码一一对应(见 RestRequestExtensions.File.cs):磁盘路径重载调用FileParameter.FromFile,字节与流重载调用FileParameter.Create。
请记住:AddFile会设置所有必要的头,因此不要手动设置内容头。
你还可以为AddFile调用提供文件上传选项,选项如下:
DisableFilenameEncoding(默认false):设为true时,RestSharp 不会对Content-Disposition头中的文件名进行编码;DisableFilenameStar(默认true):设为true时,RestSharp 不会向Content-Disposition头添加filename*参数。
FileParameterOptions类定义见 FileParameter.cs,两个选项默认值分别为false与true。选项使用示例:
var options = new FileParameterOptions { DisableFilenameEncoding = true, DisableFilenameStar = false }; request.AddFile("file", filePath, options: options);上面代码中的选项组合通常有助于上传文件名含非 ASCII 字符的文件——DisableFilenameEncoding = true避免对文件名做百分号编码,DisableFilenameStar = false允许添加filename*参数,使服务器能正确识别带非 ASCII 字符的原始文件名。
延伸阅读
- 请求执行与响应处理:见 usage/execute.md 与 usage/response.md
- 客户端配置与基础用法:见 usage/client.md 与 usage/basics.md
- 序列化与内容类型:见 advanced/serialization.md
- 相关核心源码:RestRequest.cs、RestRequestExtensions.Body.cs、RestRequestExtensions.File.cs、PropertyCache.Populator.cs、ObjectParser.cs
- 后端
- API设计
【免费下载链接】RestSharp
Simple REST and HTTP API Client for .NET
相关推荐
Litestar HTTP 请求体处理实战:data 参数、Body 注解、文件上传与请求体大小限制
Litestar HTTP 请求体处理实战:data 参数、Body 注解、文件上传与请求体大小限制 本文围绕 Litestar 官方的 Request 文档(
后端Web框架TypeSpec HTTP 库 Multipart 请求完整指南:从 @multipartBody 到 HttpPart 文件上传
TypeSpec HTTP 库 Multipart 请求完整指南:从 @multipartBody 到 HttpPart 文件上传 导读 :本文以 TypeSp
编程语言编译器后端终极指南:如何用Alamofire轻松构建iOS网络请求
终极指南:如何用Alamofire轻松构建iOS网络请求 Alamofire是一个用于iOS和macOS的网络库,提供了RESTful API的封装和SDK,帮
网络通信后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考