# HttpClient扩展 **Repository Path**: zijian666/httpclient-extensions ## Basic Information - **Project Name**: HttpClient扩展 - **Description**: 以最优雅,最便捷的方式调用HTTP接口。 - **Primary Language**: C# - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 15 - **Forks**: 1 - **Created**: 2020-09-15 - **Last Updated**: 2025-04-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Http扩展方法 ### 介绍 扩展原生`HttpClient`,`HttpMessageHandler`,`HttpResponseMessage`等; 以最优雅,最便捷的方式调用HTTP接口。 利用.NET扩展方法的语法糖,扩展.NET原生对象; 最大程度的避免对原有代码的污染,也方便与其他第三方组件库联动。 ### 更新日志 [点击查看](UPLOGS.md) ### 安装教程 [nuget - zijian666.HttpClientExtensions](https://www.nuget.org/packages/zijian666.HttpClientExtensions/) [nuget - zijian666.HttpClientExtensions.Convert](https://www.nuget.org/packages/zijian666.HttpClientExtensions.Convert/) ### 使用说明 ```csharp var s = http.Fluent() .BaseUrl("https://api.apiopen.top") .Path("getJoke") .Query(new { page = 1, count = 2, type = "video" }) .GetString(); // .GetStringAsync(); -- await/async ``` > 由于一步操作返回的都是只读结构体`readonly struct FluentHttpClient`, > 所以你可以在任何时间将它保存起来, > 而不必担心后续操作会改变其中的值。 #### 路由模版 ```csharp [TestMethod] public void PathTemplateTest() { var obj = new { id = 1, name = "zijian666", time = "2020-10-17 16:14:23", array = new[] { 1, 2, 3, 4, } }; using var client = new HttpClient(); var url = client.Fluent() .BaseUrl("baidu.com/a/b/c") .Path("user/{id}/name={name}/{array}/{time}", obj) .ToString("url"); Assert.AreEqual("http://baidu.com/a/b/user/1/name=zijian666/1,2,3,4/2020-10-17%2016:14:23", url); } ``` #### 上传文件 ```csharp using var client = new HttpClient(); var file = Directory.GetFiles("d:\\") .Select(x => new FileInfo(x)) .First(x => x.Length > 10240 && x.Length < 100 * 1024); var raw = client.Fluent() .BaseUrl("baidu.com") .Path("image/upload") .AddDefaultHeaders() .Form( new FormData("str", "test.jpg"), new FormData("bytes", new byte[] { 111, 222, 123 }, "ok.db"), new FormData("file", new FileInfo("d:\\1.jpg"), "image/jpg") ) .SendAsync(); ``` > 上传文件支持`Stram`,`byte[]`,`FileInfo`,前2种最好提供文件名; > 不过即使没有文件名,提交时也会使用默认文件名"stream"和"bytes"。 #### zijian666.HttpClientExtensions.Convert > 安装 [zijian666.HttpClientExtensions.Convert](https://www.nuget.org/packages/zijian666.HttpClientExtensions.Convert/) 实现`json`和动态类型`dynamic`的支持 #### JSON ```csharp var obj = new { id = 1, name = "zijian666", time = "2020-10-17 16:14:23", array = new[] { 1, 2, 3, 4, } }; using var client = new HttpClient(); var raw = client.Fluent() .BaseUrl("baidu.com") .Path("get/user") .AddDefaultHeaders() .JsonBody(obj) .ToString(); Console.WriteLine(raw); ``` ```text GET http://baidu.com/get/user 1.1 Content-Type: application/json; charset=utf-8 User-Agent: .NET-Framework/3.1.8,(Microsoft Windows NT 10.0.19041.0; WOW64),zijian666.HttpClientExtensions/1.0.0.0,(BLQW-XIAOMIGTX; blqw) Accept: */* Accept-Encoding: gzip,deflate Accept-Language: zh-CN,zh; q=0.8 {"id":1,"name":"zijian666","time":"2020-10-17 16:14:23","array":[1,2,3,4]} ``` #### 动态类型 dynamic ```csharp using var http = new HttpClient(); var s = http.Fluent() .BaseUrl("https://api.apiopen.top") .Path("getJoke") .Query(new { page = 1, count = 2, type = "video" }) .GetDynamic(); Console.WriteLine(s); Console.WriteLine($"code = {s.code}"); Console.WriteLine($"message = {s.message}"); ``` ```text {"code":200,"message":"\u6210\u529F!","result":[{"sid":"31568775","text":"\u8FFD\u94F6\u884C\u5C0F\u59D0\u59D0\u5168\u8FC7\u7A0B\uFF0C\u770B\u4EBA\u5BB6\u662F\u600E\u4E48\u8FFD\u5973\u5B69\u7684\u3002","type":"video","thumbnail":"http://wimg.spriteapp.cn/picture/2020/0903/84bbafce-ed8f-11ea-8969-1866daeb0df0_wpd.jpg","video":"http://uvideo.spriteapp.cn/video/2020/0903/84bbafce-ed8f-11ea-8969-1866daeb0df0_wpd.mp4","images":{},"up":"396","down":"12","forward":"18","comment":"27","uid":"22904192","name":"\u767E\u601D\u7206\u7B11","header":"http://wimg.spriteapp.cn/profile/20180809175405412650.jpg","top_comments_content":{},"top_comments_voiceuri":{},"top_comments_uid":{},"top_comments_name":{},"top_comments_header":{},"passtime":"2020-09-17 21:10:05"},{"sid":"31568566","text":"\u5144\u5F1F\u4EEC\uFF0C\u600E\u4E48\u628A\u6211\u7684\u804C\u4E1A\u8BF4\u5F97\u9AD8\u7AEF\u4E00\u4E9B\uFF1F","type":"video","thumbnail":"http://wimg.spriteapp.cn/picture/2020/0902/d39a6c04-ecc5-11ea-ac6c-1866daeb0df0_wpd.jpg","video":"http://uvideo.spriteapp.cn/video/2020/0902/d39a6c04-ecc5-11ea-ac6c-1866daeb0df0_wpd.mp4","images":{},"up":"277","down":"3","forward":"10","comment":"27","uid":"20620899","name":"\u9047\u4E00\u72D7\u767D\u9996","header":"http://wimg.spriteapp.cn/profile/20190318103732351696.jpeg","top_comments_content":"\u795E\u519C","top_comments_voiceuri":"","top_comments_uid":"22956417","top_comments_name":"\u5468\u6B63\u6D0B","top_comments_header":"http://wimg.spriteapp.cn/profile","passtime":"2020-09-17 21:00:05"}]} code = 200 message = 成功! ``` ### 扩展性 阅读 [FluentHttpClient](src/zijian666.HttpClientExtensions/FluentHttpClient.cs) 和 [HttpClientExtensions](src/zijian666.HttpClientExtensions/HttpClientExtensions.cs) 你也可以很轻松的写出扩展方法。 参考: ```csharp public static FluentHttpClient AddDefaultHeaders(this FluentHttpClient fluent) { return fluent.DefaultHeader("Accept", "*/*") .DefaultHeader("Accept-Encoding", "gzip, deflate") .DefaultHeader("Accept-Language", "zh-CN,zh;q=0.8"); } public static Task GetStringAsync(this FluentHttpClient fluent) => fluent.Method("Get").SendAsync().ReadAsStringAsync(); ```