御帝哥哥 發表於 2019-10-11 20:39:00

C# HttpClient 请求认证、数据传输笔记

<p>C# HttpClient 请求认证、数据传输笔记</p>
<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>一,授权认证<ul><li><ul><li>1. 基础认证示例</li><li>2. JWT 认证示例</li><li>3. Cookie 示例</li></ul></li></ul></li><li>二,请求类型</li><li>三,数据传输<ul><li><ul><li>1. Query</li><li>2. Header</li><li>3. 表单</li><li>4. JSON</li><li>5. 上传文件</li></ul></li></ul></li></ul></div><p></p>
<h2 id="一授权认证">一,授权认证</h2>
<p>客户端请求服务器时,需要通过授权认证许可,方能获取服务器资源,目前比较常见的认证方式有 Basic 、JWT、Cookie。</p>
<p>HttpClient 是 C# 中的 HTTP/HTTPS 客户端,用于发送 HTTP 请求和接收来自通过 URI 确认的资源的 HTTP 响应。下面以具体代码做示范。</p>
<h4 id="1-基础认证示例">1. 基础认证示例</h4>
<pre><code class="language-c#">      // 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();
      }
</code></pre>
<p>可以看到 Basic 认证的安全程度非常低,多用于路由器和嵌入式设备,而且往往不会使用 HTTPS。</p>
<h4 id="2-jwt-认证示例">2. JWT 认证示例</h4>
<pre><code class="language-c#">      // 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 证书,但是证书不安全,则需要使用下面语句
            // =&gt; 也就是说,不校验证书,直接允许
            httpclientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, error) =&gt; 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();
            }
      }
</code></pre>
<p>JWT 认证,需要客户端携带 token ,token 是一段加密过的字符串,关于原理这里不多说,token 是通过客户端 header 携带的。</p>
<p>另外,对于测试的 Web 应用或者内网应用, HTTPS 证书可能不是公网国际认证的证书,就需要跳过认证,直接允许访问使用。</p>
<pre><code class="language-c#">            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) =&gt; true,
            };
</code></pre>
<h4 id="3-cookie-示例">3. Cookie 示例</h4>
<p>HttpClient 中,Cookie 有两种处理方式。</p>
<p>一种是已经知道 Cookie ,直接将 Cookie 存储到 HttpClient 中;另一种是还没有 Cookie ,通过账号密码登录获取到 Cookie ,自动存储到 HttpClient 对象中,接着使用当前 HttpClient 对象请求 URL。</p>
<p>两种方式的设定,是通过 HttpClientHandler 的 UseCookies 属性设置的。</p>
<p>示例</p>
<pre><code class="language-c#">            var httpclientHandler = new HttpClientHandler()
            {
                UseCookies = true
            };
</code></pre>
<p>​         UseCookies 获取或设置一个值,该值指示处理程序是否使用 CookieContainer 属性存储服务器 Cookie,并在发送请求时使用这些 Cookie。</p>
<p>方式1:</p>
<pre><code class="language-c#">      // 先用账号密码登陆再请求
      public async Task Cookie(string user, string password, string loginUrl, string url)
      {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) =&gt; true,
                UseCookies = true
            };
            // 如果服务器有 https 证书,但是证书不安全,则需要使用下面语句
            // =&gt; 也就是说,不校验证书,直接允许

            var loginContent = new FormUrlEncodedContent(new[]
            {
             new KeyValuePair&lt;string,string&gt;("user",user),
             new KeyValuePair&lt;string, string&gt;("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();
            }
      }
</code></pre>
<p>方式2:</p>
<pre><code class="language-c#">      //已经拿到 cookie ,直接使用 cookie 请求
      public async Task Cookie(string cookie, string url)
      {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) =&gt; true,
                UseCookies = false
            };
            // 如果服务器有 https 证书,但是证书不安全,则需要使用下面语句
            // =&gt; 也就是说,不校验证书,直接允许


            using (var httpClient = new HttpClient(httpclientHandler))
            {
                httpClient.DefaultRequestHeaders.Add("Cookie", cookie);
                await httpClient.GetAsync(url);
                httpClient.Dispose();
            }
      }
</code></pre>
<h2 id="二请求类型">二,请求类型</h2>
<p>HTTP 请求里,有 GET、POST、DELETE、PUT 等请求方式。</p>
<p>HttpClient 中,有以下请求相关的方法</p>
<ol>
<li>CancelPendingRequests</li>
<li>DeleteAsync</li>
<li>GetAsync</li>
<li>GetByteArrayAsync</li>
<li>GetStreamAsync</li>
<li>GetStringAsync</li>
<li>PostAsync</li>
<li>PutAsync</li>
<li>SendAsync</li>
</ol>
<p>其中, CancelPendingRequests 是取消该实例所有挂起的请求,不是请求类型。</p>
<p>SendAsync 用于处理送 HttpRequestMessage(表示一条 HTTP 请求消息),比较原生。</p>
<p><img src="https://img2018.cnblogs.com/blog/1315495/201910/1315495-20191011202239404-1456868843.jpg" alt="s" loading="lazy"></p>
<p>对于 GetAsync、PostAsync等请求方法,使用过程类似,下面是使用示例</p>
<pre><code class="language-c#">      public async void Request(string url)
      {

            using (var httpClient = new HttpClient())
            {
                // HttpClient 中,所有 Get 请求都是异步的
                HttpResponseMessage result = await httpClient.GetAsync(url);

                // Task&lt;&gt;.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&lt;string,string&gt;("Email","123@qq.com"),
                  new KeyValuePair&lt;string, string&gt;("Number","666")
                });
                // 使用 Post ,必须携带 继承 HttpContent 的对象
                // 就是说,Post 必须要上传数据
                result = await httpClient.PostAsync(url, fromContent);

                // 如果没有数据要上传,可以使用 null
                result = await httpClient.PostAsync(url, null);


                httpClient.Dispose();
            }
</code></pre>
<h2 id="三数据传输">三,数据传输</h2>
<p>HTTP/HTTPS 请求中,往往随着数据传输,例如表单提交、JSON上传、文件上传等,下面以代码示范。</p>
<h4 id="1-query">1. Query</h4>
<p>ASP.NET Core API 可以这样写</p>
<pre><code class="language-c#">      
      public async Task&lt;JsonResult&gt; 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 });
      }
</code></pre>
<p>HttpClient</p>
<pre><code class="language-c#">      // URL Query 参数
      public void Query(string a, string b)
      {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) =&gt; true,
            };
            using (var httpClient = new HttpClient(httpclientHandler))
            {

                var result = httpClient.PostAsync($"https://localhost:5001/test?a={a}&amp;b={b}", null).Result;

                httpClient.Dispose();
            }
      }
</code></pre>
<h4 id="2-header">2. Header</h4>
<p>Header 是以键值形式存储的,HttpClient 示例</p>
<pre><code class="language-c#">      // Header 头
      public void Header()
      {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) =&gt; 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();
            }
      }
</code></pre>
<p>ASP.NET Core API 示例</p>
<pre><code class="language-c#">      
      public async Task&lt;JsonResult&gt; DDD(int? a, int? b)
      {
            if (a == null || b == null)
                return new JsonResult(new { code = 0, result = "aaaaaaaa" });
            return new JsonResult(new { code = 200, result = a + "|" + b });
      }

</code></pre>
<h4 id="3-表单">3. 表单</h4>
<pre><code class="language-c#">      //表单提交
      // application/x-www-form-urlencoded
      public void From()
      {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) =&gt; true,
            };

            var fromContent = new FormUrlEncodedContent(new[]
            {
             new KeyValuePair&lt;string,string&gt;("Id","1"),
             new KeyValuePair&lt;string,string&gt;("Name","痴者工良"),
             new KeyValuePair&lt;string, string&gt;("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();
            }
      }
</code></pre>
<h4 id="4-json">4. JSON</h4>
<p>除了 JSON ,还有</p>
<ul>
<li>text/html<br>
application/javascript<br>
text/plain<br>
application/xml</li>
</ul>
<p>他们都是使用 StringContent 来表示。</p>
<pre><code class="language-c#">      // Json 等
      public void StringAnd(string json)
      {
            var httpclientHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, error) =&gt; 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();
            }
      }
</code></pre>
<h4 id="5-上传文件">5. 上传文件</h4>
<p>API 这样写</p>
<pre><code class="language-c#">          //上传文件是 post 方式,这里加不加都可以
      public async Task&lt;IActionResult&gt; UploadFiles(List&lt;IFormFile&gt; files)
      {
      // ...
      }
</code></pre>
<p>HttpClient 写法</p>
<pre><code class="language-c#">      // 上传文件
      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 写法是
               * (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);
                }
            }
      }
</code></pre>


</div>
<div id="MySignature" role="contentinfo">
    痴者工良(https://whuanle.cn)<br><br>
来源:https://www.cnblogs.com/whuanle/p/11656734.html
頁: [1]
查看完整版本: C# HttpClient 请求认证、数据传输笔记