C# abp框架Http辅助类

这篇具有很好参考价值的文章主要介绍了C# abp框架Http辅助类。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、定义接口

为什么要定义接口而不直接使用静态类,因为接口可以注入缓存对象,这样就能从缓存中读取指定的请求头

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace Test.Common
{
    /// <summary>
    /// HTTP请求接口
    /// </summary>
    public interface IHttpClientUtils: IApplicationService
    {
        /// <summary>
        /// 发送HTTP请求,注意Get请求第4个参数才是缓存key,因此第3个参数请设置为null
        /// </summary>
        /// <param name="method">HttpMethod.Get、HttpMethod.Post、HttpMethod.Put、HttpMethod.Delete</param>
        /// <param name="url">完整地址</param>
        /// <param name="model">请求体对象</param>
        /// <param name="cacheKey">鉴权请求头缓存key</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        Task<T> SendAsync<T>(HttpMethod method, string url, object model = null, string cacheKey = "", Dictionary<string, string> headers = null);


        /// <summary>
        /// 发送HTTP表单请求
        /// </summary>
        /// <param name="method">HttpMethod.Post、HttpMethod.Put</param>
        /// <param name="url">完整地址</param>
        /// <param name="model">请求体对象</param>
        /// <param name="cacheKey">鉴权请求头缓存key</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        Task<T> SendFormAsync<T>(HttpMethod method, string url, object model, string cacheKey = "", Dictionary<string, string> headers = null);
    }
}

二、实现接口

1、支持https

2、支持从缓存读取鉴权请求头

3、支持对象携带文件上传

using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using RestSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.Json;

namespace Test.Common
{
    /// <summary>
    /// HTTP请求实现
    /// </summary>
    public class HttpClientUtils: ApplicationService, IHttpClientUtils
    {
        private readonly ILogger<HttpClientUtils> _logger;
        private readonly IDistributedCache<Dictionary<string, string>> _cache;
        public HttpClientUtils(
            ILogger<HttpClientUtils> logger,
            IDistributedCache<Dictionary<string, string>> cache) 
        {
            _cache = cache;
            _logger = logger;
        }

        /// <summary>
        /// 发送HTTP请求
        /// </summary>
        /// <param name="method">HttpMethod.Get、HttpMethod.Post、HttpMethod.Put、HttpMethod.Delete</param>
        /// <param name="url">完整地址</param>
        /// <param name="model">请求体对象</param>
        /// <param name="cacheKey">鉴权请求头缓存key</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<T> SendAsync<T>(HttpMethod method, string url, object model = null, string cacheKey = "", Dictionary<string, string> headers = null)
        {
            _logger.LogInformation($"SendAsync {method.Method} url = {url}, cacheKey = {cacheKey}, data = {JsonConvert.SerializeObject(model)}");
            try
            {
                using (var client = new HttpClient())
                {
                    if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
                    { 
                        url = $"http://{url}";
                    }
                    using (var request = new HttpRequestMessage(method, url))    
                    {
                        if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                        {
                            SetHttps();
                        }

                        var sc = new StreamContent(new MemoryStream());
                        if (model != null)
                        {
                            var jsonStr = JsonConvert.SerializeObject(model);
                            var bytes = Encoding.UTF8.GetBytes(jsonStr);
                            sc = new StreamContent(new MemoryStream(bytes));
                        }

                        HeaderHandler(request, sc.Headers, "application/json", headers, cacheKey);

                        request.Content = sc;
                        var rsp = await client.SendAsync(request);
                        return ResponseHandler<T>(rsp);
                    }
                }
            }
            catch (Exception e)
            {
                _logger.LogError($"SendAsync {method.Method} 请求:{url}, 错误消息:{e.Message}, 请求参数:{JsonConvert.SerializeObject(model)}");
                throw new Exception($"请求HTTP服务{new Uri(url).AbsolutePath}异常:{e.Message}");
            }
        }

        
        /// <summary>
        /// 发送HTTP表单请求
        /// </summary>
        /// <param name="method">HttpMethod.Post、HttpMethod.Put</param>
        /// <param name="url">完整地址</param>
        /// <param name="model">请求体对象</param>
        /// <param name="cacheKey">鉴权请求头缓存key</param>
        /// <param name="headers">请求头</param>
        /// <returns></returns>
        public async Task<T> SendFormAsync<T>(HttpMethod method, string url, object model, string cacheKey = "", Dictionary<string, string> headers = null)
        {
            _logger.LogInformation($"SendFormAsync {method.Method} url = {url}, cacheKey = {cacheKey}, data = {JsonConvert.SerializeObject(model)}");
            try
            {
                var client = new RestClient();
                var request = new RestRequest(url, Method.POST);
                if (method == HttpMethod.Put)
                {
                    request.Method = Method.PUT;
                }
                
                SetHeader(request, cacheKey, headers);
                request.AlwaysMultipartFormData = true;

                var props = model.GetType().GetProperties();
                foreach (var item in props)
                {
                    var k = item.Name;
                    var v = item.GetValue(model);

                    if (v == null)
                    {
                        _logger.LogInformation($"SendFormAsync {method.Method} url = {url} {k} value is null");
                        continue;
                    }

                    if (v.GetType().Name == "Dictionary`2") // 文件只支持字典类型
                    {
                        if (v is Dictionary<string, byte[]>) 
                        {
                            var files = v as Dictionary<string, byte[]>;
                            foreach (var obj in files) // 多个文件只能一个个添加,不能集合到List中
                            {
                                string ext = Path.GetExtension(obj.Key);
                                ext = ext.RemovePreFix(".");

                                _logger.LogInformation($"SendFormAsync file key = {k}, name = {obj.Key}, ext = {ext}, size = {obj.Value.Length}");

                                request.AddFileBytes(k, obj.Value, obj.Key, $"image/{ext}");
                            }
                        }
                    }
                    else
                    {
                        request.AddParameter(k, v);
                    }
                }

                var response = await client.ExecuteAsync(request);
                if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Created)
                {
                    _logger.LogError($"SendFormAsync {method.Method} {url} 响应失败: {response.Content}");
                    throw new Exception($"服务器响应失败:status = {response.StatusCode}");
                }

                _logger.LogInformation($"SendFormAsync {method.Method} {url} Response: {response.Content}");

                return JsonConvert.DeserializeObject<T>(response.Content, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
            }
            catch (Exception e)
            {
                _logger.LogError($"SendFormAsync {method.Method} 请求:{url}, 错误消息:{e.Message}, 请求参数:{JsonConvert.SerializeObject(model)}");
                throw new Exception($"请求HTTP服务{new Uri(url).AbsolutePath}异常:{e.Message}");
            }
        }

        /// <summary>
        /// 设置请求头
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cacheKey"></param>
        private void SetHeader(RestRequest request, string cacheKey, Dictionary<string, string> headers)
        {
            // 鉴权请求头
            var cacheHeaders = _cache.Get(cacheKey);
            if (cacheHeaders != null)
            {
                foreach (var dic in cacheHeaders)
                {
                    _logger.LogInformation($"SetHeader cache header: {dic.Key} = {dic.Value}");

                    if (dic.Key.Equals("authorization", StringComparison.OrdinalIgnoreCase))
                    {
                        request.AddHeader("Authorization", dic.Value);
                    }
                    else
                    {
                        request.AddHeader(dic.Key, dic.Value);
                    }
                }
            }

            // 默认请求头
            if (headers != null && headers.Count > 0)
            {
                foreach (var dic in headers)
                {
                    request.AddHeader(dic.Key, dic.Value);
                }
            }
        }

        /// <summary>
        /// 处理请求头
        /// </summary>
        /// <param name="request">new HttpRequestMessage</param>
        /// <param name="contentHeader">new MultipartFormDataContent</param>
        /// <param name="contentType">multipart/form-data</param>
        /// <param name="headers">Dictionary<string, string></param>
        /// <param name="cacheKey">authorization</param>
        private void HeaderHandler(HttpRequestMessage request, HttpContentHeaders contentHeader, string contentType, Dictionary<string, string> headers, string cacheKey)
        {
            // 添加默认请求头
            if (headers != null && headers.ContainsKey("Content-Type"))
            {
                contentType = headers["Content-Type"];
            }

            if (string.IsNullOrEmpty(contentType)) 
            {
                contentType = "application/json"; // 默认application/json
            }

            _logger.LogInformation($"HeaderHandler {request.Method.Method} {request.RequestUri.AbsolutePath} default contentType header: {contentType}");

            if (contentType.IndexOf("multipart/form-data") != -1)
            {
                contentHeader.Remove("Content-Type"); // MediaTypeHeaderValue不支持解析boundary,所以先删除再Add
                contentHeader.TryAddWithoutValidation("Content-Type", contentType);
            }
            else
            {
                contentHeader.ContentType = new MediaTypeHeaderValue(contentType); 
            }

            // 添加鉴权请求头
            var cacheHeaders = _cache.Get(cacheKey);
            if (cacheHeaders != null)
            {
                foreach (var dic in cacheHeaders)
                {
                    _logger.LogInformation($"HeaderHandler {request.Method.Method} {request.RequestUri.AbsolutePath} cache header: {dic.Key} = {dic.Value}");

                    if (dic.Key.Equals("authorization", StringComparison.OrdinalIgnoreCase))
                    {
                        request.Headers.Authorization = new AuthenticationHeaderValue(dic.Value);
                        // request.SetBearerToken(dic.Value); // 这个方法里加了前缀Bearer,针对接口不同
                    }
                    else
                    {
                        contentHeader.Add(dic.Key, dic.Value); // cookie、token ...
                    }
                }
            }

            // 添加参数请求头
            if (headers != null && headers.Count > 0)
            {
                foreach (var dic in headers)
                {
                    if (contentHeader.ContentType.MediaType == dic.Value)
                    {
                        continue;
                    }
                    contentHeader.Add(dic.Key, dic.Value);
                }
            }
        }

        /// <summary>
        /// 处理HTTP响应
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="rsp"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private T ResponseHandler<T>(HttpResponseMessage rsp)
        {
            if (rsp.StatusCode != HttpStatusCode.OK && rsp.StatusCode != HttpStatusCode.Created)
            {
                _logger.LogError($"ResponseHandler {rsp.RequestMessage.Method.Method} {rsp.RequestMessage.RequestUri.AbsoluteUri} 响应失败: {rsp.Content.ReadAsStringAsync().Result}");
                throw new Exception($"服务器响应失败:status = {rsp.StatusCode}");
            }

            if (rsp is T)
            {
               return (T)(object)rsp;  // 返回HttpResponseMessage,用于获取响应头
            }
            else
            {
                var json = rsp.Content.ReadAsStringAsync().Result;
                _logger.LogInformation($"ResponseHandler {rsp.RequestMessage.Method.Method} {rsp.RequestMessage.RequestUri.AbsoluteUri} 响应:{json}");
                return JsonConvert.DeserializeObject<T>(json, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
                // return rsp.Content.ReadFromJsonAsync<T>().Result; // 会检查int null类型报错
            }
        }

        /// <summary>
        /// 设置HTTPS
        /// </summary>
        private void SetHttps()
        {
            // set remote certificate Validation auto pass
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(RemoteCertificateValidate);
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
            // FIX:修复不同.Net版对一些SecurityProtocolType枚举支持情况不一致导致编译失败等问题,这里统一使用数值
            //ServicePointManager.SecurityProtocol = (SecurityProtocolType)48 | (SecurityProtocolType)3072 | (SecurityProtocolType)768 | (SecurityProtocolType)192;
        }

        /// <summary>
        /// 远程证书验证
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="cert"></param>
        /// <param name="chain"></param>
        /// <param name="error"></param>
        /// <returns>验证是否通过,始终通过</returns>
        private bool RemoteCertificateValidate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
        {
            return true;
        }
    }
}

三、遇到问题

1、无法添加请求头content-type

var s = new HttpRequestMessage()
s.Headers.Add("Content-Type", "")
报错:Misused header name, 'Content-Type'. Make sure request headers are used with HttpRequestMessage,

var b = new HttpContentHeader()
b.Add("Content-Type", "")
报错:Cannot add value because header 'Content-Type' does not support multiple values.

var b = new HttpContentHeader()
b.ContentType = new MediaTypeHeaderValue("multipart/form-data; boundary=----8db27a5c21ea4f8");
报错:The format of value 'multipart/form-data; boundary=----8db27a5c21ea4f8' is invalid
报错:'multipart/form-data; ----8db27a507065123' is invalid
报错:'multipart/form-data; boundary=--8db27ca4cfafb57' is invalid

1、解决方案:

请看方法:HeaderHandler

 文章来源地址https://www.toymoban.com/news/detail-425050.html

到了这里,关于C# abp框架Http辅助类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 为什么 HTTPS 比 HTTP 安全

    HTTP(超文本传输协议)是目前互联网应用最广泛的协议,伴随着人们网络安全意识的加强,HTTPS 被越来越多地采纳。不论是访问一些购物网站,或是登录一些博客、论坛等,我们都被 HTTPS 保护着,甚至 Google Chrome、Firefox 等主流浏览器已经将所有基于 HTTP 的站点都标记为不安全

    2024年02月19日
    浏览(52)
  • 为什么有了 HTTP 还要 RPC

    哈喽大家好,我是咸鱼 随着互联网技术的发展,分布式架构越来越被人们所采用。在分布式架构下, 为了实现复杂的业务逻辑,应用程序需要分布式通信实现远程调用 而这时候就需要一种协议来支持远程过程调用,以便实现不同应用程序之间的数据交换和信息传递。其中常

    2024年02月05日
    浏览(48)
  • 为什么 https 比 http 更安全?

    http 和 https 在许多网站都有用到,但是现在都是极力倡导使用 https ,究其原因就是 http 的安全性不够高,在数据传输过程中可能会遭到黑客窃取。 本篇文章会先讲解 http 缺点,然后再讲解 https 是如何解决这些问题来保证安全的。 一、http 缺点 通信使用明文(不加密),内容

    2024年01月24日
    浏览(48)
  • 爬虫为什么需要 HTTP 代理 IP?

    前言 爬虫在互联网数据采集、分析和挖掘中扮演着至关重要的角色,但是对于目标网站而言,频繁的爬虫请求可能会对其服务器产生不小的负担,严重的情况甚至会导致网站崩溃或者访问受限。为了避免这种情况的发生,同时也为了保护客户端的隐私和安全,爬虫使用HTTP代

    2024年02月07日
    浏览(50)
  • 为什么接口宁拆分不和并?

    注:删除/修改就需要理清楚该接口/pojo类相关的每一行(否则非常容易导致修改一个功能时直接导致另外的功能错误,甚至系统奔溃),对比修改一个接口只看当前接口代码不需要关注其他代码影响的功能来说,维护成本低了太多(相比而言,在各个模块穿插交互的项目里,只看一个功能

    2024年02月13日
    浏览(50)
  • Go 接口:nil接口为什么不等于nil?

    本文主要内容:深入了解接口类型的运行时表示层。 目录 Go 接口:nil接口为什么不等于nil? 一、Go 接口的地位 二、接口的静态特性与动态特性 2.1 接口的静态特性与动态特性介绍 2.2 “动静皆备”的特性的好处 三、nil error 值 != nil 四、接口类型变量的内部表示 第一种:nil 接

    2024年02月05日
    浏览(74)
  • HTTP协议演进:为什么说HTTP/1.1的时代已经过去了

    前言   欢迎来到今天的每日一题,每日一提。昨天聊到了,HTTP 是什么。有哪些组成部分。并且最后提到了 HTTP 的一些缺点,比如:性能较低,容易导致网络拥塞和延迟,不支持服务器推送等等。设计协议的大佬们,对这样的缺点肯定是不能容忍的,所以 HTTP2 它来了。 什

    2023年04月17日
    浏览(41)
  • C#为什么非要把函数叫方法?

    引子 \\\"某呼\\\"网友提问“C#为什么非要把函数叫方法?”,看到这个问题还真不知道怎么回答。要想知道C#为什么叫方法,还得从传统面向过程语言说起。 方法的由来 函数(function)是面向过程编程语言里,对可以独立调用代码段的另一种叫法,因为通常有数个输入和一个输出

    2024年02月09日
    浏览(44)
  • 【走进Java框架】什么是Java框架,为什么要学习Java框架.

    前言: 大家好,我是 良辰丫 ,今天我们就要开始Java框架之旅了,我们在学习的征途中不断充实自己,提升自己的能力,加油哈,自我勉励一下,跟随我的步伐,一起前行哈.💌💌💌 🧑个人主页:良辰针不戳 📖所属专栏:javaEE进阶篇之框架学习 🍎励志语句:生活也许会让我们遍体鳞

    2024年02月07日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包