C# HttpClient 請求認證、數據傳輸筆記


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,
            };

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 中,有以下請求相關的方法

  1. CancelPendingRequests
  2. DeleteAsync
  3. GetAsync
  4. GetByteArrayAsync
  5. GetStreamAsync
  6. GetStringAsync
  7. PostAsync
  8. PutAsync
  9. SendAsync

其中, CancelPendingRequests 是取消該實例所有掛起的請求,不是請求類型。

SendAsync 用於處理送 HttpRequestMessage(表示一條 HTTP 請求消息),比較原生。

s

對於 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);
                }
            }
        }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM