C#客户端HttpClient请求认证及数据传输
作者:痴者工良
一,授权认证
客户端请求服务器时,需要通过授权认证许可,方能获取服务器资源,目前比较常见的认证方式有 Basic 、JWT、Cookie。
HttpClient 是 C# 中的 HTTP/HTTPS 客户端,用于发送 HTTP 请求和接收来自通过 URI 确认的资源的 HTTP 响应。下面以具体代码做示范。
1. 基础认证示例
// Basic基础认证 public async Task Basic(string user, string password, string url) { // 如果认证页面是 https 的,请参考一下 jwt 认证的 HttpClientHandler // 创建 client HttpClient client = new HttpClient(); // 创建身份认证 // using System.Net.Http.Headers; AuthenticationHeaderValue authentication = new AuthenticationHeaderValue( "Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{user}:{password}") )); client.DefaultRequestHeaders.Authorization = authentication; byte[] response = await client.GetByteArrayAsync(url); client.Dispose(); }
可以看到 Basic 认证的安全程度非常低,多用于路由器和嵌入式设备,而且往往不会使用 HTTPS。
2. JWT 认证示例
// Jwt认证 public async Task Bearer(string token, string url) { // HttpClientHandler及其派生类使开发人员能够配置各种选项, 包括从代理到身份验证。 // helpLink https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler?view=netframework-4.8 var httpclientHandler = new HttpClientHandler(); // 如果服务器有 https 证书,但是证书不安全,则需要使用下面语句 // => 也就是说,不校验证书,直接允许 httpclientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true; using (var httpClient = new HttpClient(httpclientHandler)) { // 创建身份认证 // System.Net.Http.Headers.AuthenticationHeaderValue; httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); await httpClient.GetAsync(url); httpClient.Dispose(); } }
JWT 认证,需要客户端携带 token ,token 是一段加密过的字符串,关于原理这里不多说,token 是通过客户端 header 携带的。
另外,对于测试的 Web 应用或者内网应用, HTTPS 证书可能不是公网国际认证的证书,就需要跳过认证,直接允许访问使用。
var httpclientHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true, };
3. Cookie 示例
HttpClient 中,Cookie 有两种处理方式。
一种是已经知道 Cookie ,直接将 Cookie 存储到 HttpClient 中;另一种是还没有 Cookie ,通过账号密码登录获取到 Cookie ,自动存储到 HttpClient 对象中,接着使用当前 HttpClient 对象请求 URL。
两种方式的设定,是通过 HttpClientHandler 的 UseCookies 属性设置的。
示例
var httpclientHandler = new HttpClientHandler() { UseCookies = true };
UseCookies 获取或设置一个值,该值指示处理程序是否使用 CookieContainer 属性存储服务器 Cookie,并在发送请求时使用这些 Cookie。
方式1:
// 先用账号密码登陆再请求 public async Task Cookie(string user, string password, string loginUrl, string url) { var httpclientHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true, UseCookies = true }; // 如果服务器有 https 证书,但是证书不安全,则需要使用下面语句 // => 也就是说,不校验证书,直接允许 var loginContent = new FormUrlEncodedContent(new[] { new KeyValuePair<string,string>("user",user), new KeyValuePair<string, string>("password",password) }); using (var httpClient = new HttpClient(httpclientHandler)) { // 先登陆 var result = await httpClient.PostAsync(loginUrl, loginContent); // 登陆成功后,客户端会自动携带 cookie ,不需要再手动添加 //if (result.IsSuccessStatusCode) //{ // /* // * 如果请求成功 // */ //} var result2 = await httpClient.GetAsync(url); // httpclient 已经携带 Cookie ,可以多次使用 // var result3 = await httpClient.GetAsync(url3); // var result4 = await httpClient.GetAsync(url4); httpClient.Dispose(); } }
方式2:
//已经拿到 cookie ,直接使用 cookie 请求 public async Task Cookie(string cookie, string url) { var httpclientHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true, UseCookies = false }; // 如果服务器有 https 证书,但是证书不安全,则需要使用下面语句 // => 也就是说,不校验证书,直接允许 using (var httpClient = new HttpClient(httpclientHandler)) { httpClient.DefaultRequestHeaders.Add("Cookie", cookie); await httpClient.GetAsync(url); httpClient.Dispose(); } }
二,请求类型
HTTP 请求里,有 GET、POST、DELETE、PUT 等请求方式。
HttpClient 中,有以下请求相关的方法
- CancelPendingRequests
- DeleteAsync
- GetAsync
- GetByteArrayAsync
- GetStreamAsync
- GetStringAsync
- PostAsync
- PutAsync
- SendAsync
其中, CancelPendingRequests 是取消该实例所有挂起的请求,不是请求类型。
SendAsync 用于处理送 HttpRequestMessage(表示一条 HTTP 请求消息),比较原生。
对于 GetAsync、PostAsync等请求方法,使用过程类似,下面是使用示例
public async void Request(string url) { using (var httpClient = new HttpClient()) { // HttpClient 中,所有 Get 请求都是异步的 HttpResponseMessage result = await httpClient.GetAsync(url); // Task<>.Result 可以获取异步结果 result = httpClient.GetAsync(url).Result; //var result1 = await httpClient.GetByteArrayAsync(url); //var result1 = await httpClient.GetStreamAsync(url); //var result1 = await httpClient.GetStringAsync(url); // ByteArrayContent FormUrlEncodedContent fromContent = new FormUrlEncodedContent(new[] { new KeyValuePair<string,string>("Email","123@qq.com"), new KeyValuePair<string, string>("Number","666") }); // 使用 Post ,必须携带 继承 HttpContent 的对象 // 就是说,Post 必须要上传数据 result = await httpClient.PostAsync(url, fromContent); // 如果没有数据要上传,可以使用 null result = await httpClient.PostAsync(url, null); httpClient.Dispose(); }
三,数据传输
HTTP/HTTPS 请求中,往往随着数据传输,例如表单提交、JSON上传、文件上传等,下面以代码示范。
1. Query
ASP.NET Core API 可以这样写
[HttpPost("aaa")] public async Task<JsonResult> AAA(int? a, int? b) { if (a == null || b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 2000, result = a + "|" + b }); }
HttpClient
// URL Query 参数 public void Query(string a, string b) { var httpclientHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true, }; using (var httpClient = new HttpClient(httpclientHandler)) { var result = httpClient.PostAsync($"https://localhost:5001/test?a={a}&b={b}", null).Result; httpClient.Dispose(); } }
2. Header
Header 是以键值形式存储的,HttpClient 示例
// Header 头 public void Header() { var httpclientHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true, }; using (var httpClient = new HttpClient(httpclientHandler)) { httpClient.DefaultRequestHeaders.Add("MyEmail", "123@qq.com"); var result = httpClient.GetAsync($"https://localhost:5001/test").Result; httpClient.Dispose(); } }
ASP.NET Core API 示例
[HttpPost("ddd")] public async Task<JsonResult> DDD([FromHeader]int? a, [FromHeader]int? b) { if (a == null || b == null) return new JsonResult(new { code = 0, result = "aaaaaaaa" }); return new JsonResult(new { code = 200, result = a + "|" + b }); }
3. 表单
// 表单提交 // application/x-www-form-urlencoded public void From() { var httpclientHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true, }; var fromContent = new FormUrlEncodedContent(new[] { new KeyValuePair<string,string>("Id","1"), new KeyValuePair<string,string>("Name","痴者工良"), new KeyValuePair<string, string>("Number","666666") }); using (var httpClient = new HttpClient(httpclientHandler)) { var result = httpClient.PostAsync("https://localhost:5001/test", fromContent).Result; Console.WriteLine(result.Content.ReadAsStringAsync().Result); httpClient.Dispose(); } }
4. JSON
除了 JSON ,还有
- text/html
- application/javascript
- text/plain
- application/xml
他们都是使用 StringContent 来表示。
// Json 等 public void StringAnd(string json) { var httpclientHandler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = (message, cert, chain, error) => true, }; var jsonContent = new StringContent(json); // Json 是 StringContent,上传时要指定 Content-Type 属性,除此外还有 // text/html // application/javascript // text/plain // application/xml jsonContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); using (var httpClient = new HttpClient(httpclientHandler)) { var result = httpClient.PostAsync("https://localhost:5001/test", jsonContent).Result; Console.WriteLine(result.Content.ReadAsStringAsync().Result); httpClient.Dispose(); } }
5. 上传文件
API 这样写
[HttpPost] //上传文件是 post 方式,这里加不加都可以 public async Task<IActionResult> UploadFiles(List<IFormFile> files) { // ... }
HttpClient 写法
// 上传文件 public async Task File(string filepath, string fromName, string url) { using (var client = new HttpClient()) { FileStream imagestream = System.IO.File.OpenRead(filepath); // multipartFormDataContent.Add(); var multipartFormDataContent = new MultipartFormDataContent() { { new ByteArrayContent(System.IO.File.ReadAllBytes(filepath)), // 文件流 fromName, // 对应 服务器 WebAPI 的传入参数 Path.GetFileName(filepath) // 上传的文件名称 } }; /* * 如果服务器 API 写法是 * ([FromForm]IFromFile files) * 那么上面的 fromName="files" */ // multipartFormDataContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data"); HttpResponseMessage response = await client.PostAsync(url, multipartFormDataContent); if (!response.IsSuccessStatusCode) { Console.WriteLine("up image error"); Console.WriteLine(response.RequestMessage); } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。