ASP.NET Core Web APi获取原始请求内容

简介:

我们讲过ASP.NET Core Web APi路由绑定,本节我们来讲讲如何获取客户端请求过来的内容。

ASP.NET Core Web APi捕获Request.Body内容

[HttpPost]
[Route("api/blog/jsonstring")]
public string Index([FromBody] string content)
{
    return content;
}

//或者

[HttpPost("api/blog/jsonstring")]
public string Index([FromBody] string content)
{
    return content;
}

由上图我们能够看到发出的为Post请求且Content-Type为application/json,所以此时在后台接受请求需要通过【FromBody】特性接受来自Post请求中的Body内容。这里需要特别说明的是:当在Vue利用axios发出Post请求且参数为简单类型参数时,但是在后台只能利用对象接收,即不能按照如下形式接收参数。

[HttpPost("api/blog/jsonstring")]
public int Index([FromBody] int id)
{
    return id;
}

对于简单类型参数此时无需额外再定义对象来接收,我们可以采用变通的方式来接收即动态对象。

[HttpPost("api/blog/jsonstring")]
public int Index([FromBody] dynaminc dy)
{
    var id = dy.id as int;
    return id;
}

//或者

[HttpPost("api/blog/jsonstring")]
public int Index([FromBody] JObject jo)
{
    JToken token = jo["id"];
    if(token.Type == JTokenType.Null)
    {
        // Do your logic
    }
    ......
}

上述两种方式皆可,利用JObject好处在于可判断参数是否为空情况,而dynamic可能会出现异常。如果我们想发送一个RAW字符串或者二进制数据,并且想要把它作为请求的一部分,那么这个时候就有意思,同时事情也会变得更加复杂。因为ASP.NET Core只会处理它所知道的信息,默认情况下是JSON和Form数据。 默认情况下原始数据不能直接映射到控制器上的方法参数上。什么意思呢?接下来我们若改变Content-Type为text/plain,此时将返回状态为415,如下图

那么对于此种情况,我们该如何获取请求参数呢?不幸的是,ASP NET Core不允许我们仅仅通过方法参数以任何有意义的方式捕获“原始”数据。不管怎样,我们都需要做一些自定义的Request.Body处理来获取原始数据,然后反序列化它。

我们可以捕获原始的Request.Body并从原始缓冲区中读取参数。最简而有效的方法,但不是那么明显的方法是接受不带参数的POST或PUT数据,然后从Request.Body读取原始数据:

[HttpPost("api/blog/jsonstring")]
public async Task<string> Index()
{
    var result = string.Empty;
    using (var reader = new StreamReader(Request.Body, Encoding.UTF8))
    {
        result = await reader.ReadToEndAsync();
    }
    return result;
}

若我们想要读取二进制数据,我们可如下操作。

[HttpPost("api/blog/bytes")]
public async Task<byte[]> RawBinaryData()
{
    using (var ms = new MemoryStream(2048))
    {
        await Request.Body.CopyToAsync(ms);
        return ms.ToArray();
    }
}

代码中的结果被捕获为二进制字节并以JSON返回,这也就是为什么我们会从上图看到base64编码的结果字符串伪装成二进制结果的原因。

像上述操作若很频繁我们完全可以封装起来,比如第三方调用我们接口时。封装如下:

public static class HttpRequestExtensions
{
    public static async Task<string> GetRawBodyStringAsync(this HttpRequest request, Encoding encoding = null)
    {
        if (encoding is null)
            encoding = Encoding.UTF8;

        using (var reader = new StreamReader(request.Body, encoding))
            return await reader.ReadToEndAsync();
    }
    public static async Task<byte[]> GetRawBodyBytesAsync(this HttpRequest request)
    {
        using (var ms = new MemoryStream(2048))
        {
            await request.Body.CopyToAsync(ms);
            return ms.ToArray();
        }
    }
}

如果我们期望对于原始参数使用确定的方法,那么我们还需要做更多额外的工作。也就是说需要自定义InputFormatter。在ASP.NET Core中通过使用InputFormatter来自定义格式化内容,并将自定义格式化内容注入到请求ASP.NET Core管道中,并根据特定参数类型来决定是否需要处理请求内容。最终请求运行通过则将请求主体进行反序列化。对于自定义InputFormatter需要满足以下两个条件。

(1)必须使用[FromBody]特性来触发它。

(2) 对于对应的请求内容需自定义对应处理。

public class HandleRequestBodyFormatter : InputFormatter
{
    public HandleRequestBodyFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/octet-stream"));
    }


    /// <summary>
    /// 允许 text/plain, application/octet-stream和没有Content-Type的参数类型解析到原始数据
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public override Boolean CanRead(InputFormatterContext context)
    {
        if (context == null) throw new ArgumentNullException(nameof(context));

        var contentType = context.HttpContext.Request.ContentType;
        if (string.IsNullOrEmpty(contentType) || contentType == "text/plain" ||
            contentType == "application/octet-stream")
            return true;

        return false;
    }

    /// <summary>
    /// 处理text/plain或者没有Content-Type作为字符串结果
    /// 处理application/octet-stream类型作为byte[]数组结果
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
    {
        var request = context.HttpContext.Request;
        var contentType = context.HttpContext.Request.ContentType;


        if (string.IsNullOrEmpty(contentType) || contentType == "text/plain")
        {
            using (var reader = new StreamReader(request.Body))
            {
                var content = await reader.ReadToEndAsync();
                return await InputFormatterResult.SuccessAsync(content);
            }
        }
        if (contentType == "application/octet-stream")
        {
            using (var ms = new MemoryStream(2048))
            {
                await request.Body.CopyToAsync(ms);
                var content = ms.ToArray();
                return await InputFormatterResult.SuccessAsync(content);
            }
        }

        return await InputFormatterResult.FailureAsync();
    }
}

上述自定义InputFormatter使用CanRead方法来检查要支持的请求内容类型,然后使用ReadRequestBodyAsync方法将内容进行读取并反序列化为类型结果,该结果类型在控制器中的方法参数中返回。

最后需要做的则是将我们自定义的InputFormatter注入到MVC请求管道中一切大功告成。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(o => o.InputFormatters.Insert(0, new HandleRequestBodyFormatter()));
}

通过对请求输入参数的自定义格式化处理,我们现在可以使用来自客户端Post或者Put请求且类型为text/plain, application/octet-stream或者没有类型。。下面我们来通过例子说明。

[HttpPost("api/blog/rawstring")]
public string RawRequestBodyFormatter([FromBody] string rawString)
{
    return rawString;
}

ASP.NET Core自身本来就支持application/json类型,我们通过自定义InputFormatter不过是多了对text/plain额外类型的支持而已。

[HttpPost]
[Route("api/blog/rawbytes")]
public byte[] RawBytesFormatter([FromBody] byte[] rawData)
{
    return rawData;
}


本文比较详细的讲解了在ASP.NET Core WebAPi中如何获取请求原始Body中的参数并添加了额外类型的支持,希望对阅读本文的您有所帮助。

目录
相关文章
|
7月前
|
开发框架 .NET C#
ASP.NET Core Blazor 路由配置和导航
大家好,我是码农刚子。本文系统介绍Blazor单页应用的路由机制,涵盖基础配置、路由参数、编程式导航及高级功能。通过@page指令定义路由,支持参数约束、可选参数与通配符捕获,结合NavigationManager实现页面跳转与参数传递,并演示用户管理、产品展示等典型场景,全面掌握Blazor路由从入门到实战的完整方案。
603 6
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
644 5
|
人工智能 搜索推荐 API
自学记录鸿蒙API 13:实现人脸比对Core Vision Face Comparator
在完成文本识别和人脸检测项目后,我深入学习了HarmonyOS Next API 13中的Core Vision Face Comparator API,开发了一个简单的人脸比对工具。该API能进行高精度人脸比对并给出相似度评分,应用场景广泛,如照片分类、身份认证、个性化服务等。通过初始化服务、加载图片、实现比对功能和构建用户界面,最终实现了可靠的人脸比对功能。未来计划将此技术应用于更复杂的场景,如照片管理和个性化服务,并探索与其他AI能力的结合。如果你也对人脸比对感兴趣,不妨从简单的比对功能开始,逐步实现自己的创意!
461 61
|
人工智能 自然语言处理 文字识别
自学记录鸿蒙API 13:实现智能文本识别Core Vision Text Recognition
在完成语音助手项目后,我尝试了HarmonyOS Next API 13中的Core Vision Text Recognition API,体验其强大的文本识别功能。该API支持多语言高精度识别,能快速将图像中的文本提取为结构化信息,适用于文档扫描、票据管理和实时翻译等场景。通过权限配置、初始化服务、实现识别功能和构建用户界面,我完成了文本识别应用的开发,并探索了性能优化与功能扩展。鸿蒙生态的强大支持让开发者能更便捷地实现复杂功能。未来计划将此技术应用于实际项目,如票据管理或实时翻译工具。如果你也对文本识别感兴趣,不妨一起探索!
369 11
|
人工智能 监控 安全
自学记录鸿蒙 API 13:骨骼点检测应用Core Vision Skeleton Detection
骨骼点检测技术能够从图片中识别出人体的关键骨骼点位置,如头部、肩部、手肘等,广泛应用于运动健身指导、游戏交互、医疗辅助、安全监控等领域。我决定深入学习HarmonyOS Next API 13中的Skeleton Detection API,并开发一个简单的骨骼点检测应用。通过理解API核心功能、项目初始化与配置、实现检测功能、构建用户界面,以及性能优化和功能扩展,逐步实现这一技术的应用。未来计划将其应用于健身指导和智能监控领域,探索与其他AI能力的结合,开发更智能的解决方案。如果你也对骨骼点检测感兴趣,不妨一起进步!
525 9
|
人工智能 监控 安全
自学记录鸿蒙 API 13:实现人脸检测 Core Vision Face Detector
本文介绍了基于HarmonyOS Next API 13中的Core Vision Face Detector API实现人脸检测小应用的过程。通过研究发现,该API不仅支持人脸检测框的定位,还能识别关键点(如眼睛、鼻子和嘴角位置)及人脸姿态信息。文章详细记录了开发历程,包括项目初始化、权限配置、图像加载与人脸检测、用户界面设计,以及性能优化和功能扩展的思路。应用场景涵盖身份验证、照片管理和实时交互等。未来计划将技术应用于智能照片管理工具,提供更高效的照片分类体验。欢迎对人脸检测技术感兴趣的读者一起探讨和进步。
602 7
|
开发框架 算法 中间件
ASP.NET Core 中的速率限制中间件
在ASP.NET Core中,速率限制中间件用于控制客户端请求速率,防止服务器过载并提高安全性。通过`AddRateLimiter`注册服务,并配置不同策略如固定窗口、滑动窗口、令牌桶和并发限制。这些策略可在全局、控制器或动作级别应用,支持自定义响应处理。使用中间件`UseRateLimiter`启用限流功能,并可通过属性禁用特定控制器或动作的限流。这有助于有效保护API免受滥用和过载。 欢迎关注我的公众号:Net分享 (239字符)
405 1
|
7月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
586 4
|
11月前
|
缓存 JavaScript 前端开发
鸿蒙5开发宝藏案例分享---Web开发优化案例分享
本文深入解读鸿蒙官方文档中的 `ArkWeb` 性能优化技巧,从预启动进程到预渲染,涵盖预下载、预连接、预取POST等八大优化策略。通过代码示例详解如何提升Web页面加载速度,助你打造流畅的HarmonyOS应用体验。内容实用,按需选用,让H5页面快到飞起!
|
11月前
|
JavaScript 前端开发 API
鸿蒙5开发宝藏案例分享---Web加载时延优化解析
本文深入解析了鸿蒙开发中Web加载完成时延的优化技巧,结合官方案例与实际代码,助你提升性能。核心内容包括:使用DevEco Profiler和DevTools定位瓶颈、四大优化方向(资源合并、接口预取、图片懒加载、任务拆解)及高频手段总结。同时提供性能优化黄金准则,如首屏资源控制在300KB内、关键接口响应≤200ms等,帮助开发者实现丝般流畅体验。