Web APi之HttpClient注意事项以及建议(四)

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介:

前言

之前对于用SelfHost来手动实现Web API的宿主模式,似乎不是太深入,所以本篇文章我们一起来讨论关于利用HttpClient来访问Web API上的资源来进行探讨以及注意相关事项,希望此文对你也有收获。

来自XML或Json Content的简单参数

当Web API方法中接受如String、Datetime、Int等参数类型时,但是默认情况下这些方法不会接收来自XML或者JSON Body的参数,那么结果就是导致请求失败。接下来我们来进行演示。

我们取名为Default的Web API控制器,方法以及路由注册如下:

复制代码
        [HttpPost]
        public string GetString(string message)
        {
            return message;
        }

         config.Routes.MapHttpRoute(
               name: "DefaultApi",
               routeTemplate: "api/{controller}/{action}/{message}",
               defaults: new { message = RouteParameter.Optional }
         );
复制代码

接下来我们用客户端发出POST请求以及数据来请求Web API来并返回该数据,如下:

            var client = new HttpClient();
            var postUrl = "http://localhost:23133/api/default/GetString";
            var task = client.PostAsJsonAsync<string>(postUrl,"Hello World").Result; //将参数进行序列化为JSON并发送到Request中的Body中

通过上述路由以及请求方式的配置理论上来说是能通过URI能访问到资源,但是结果却令你大跌眼镜

由上可得知,参数Message的值Hello World已经传递过来,但是此时请求响应的资源上方法的参数并未接收到且返回404未找到该方法。

上面可能效果不是太明显,我们利用Ajax传递时间来进行请求并返回该数据,方法如下:

        public HttpResponseMessage GetDateTime(DateTime time)
        {

            return Request.CreateResponse<DateTime>(HttpStatusCode.OK, time);
        }

前台请求如下(路由配置就此略过):

复制代码
       $("#btn").click(function () {
            $.ajax({
                type: "get",
                url: "http://localhost:23133/api/Default/GetDateTime",
                dataType: "json",
                contentType: "application/json; charset=utf-8",
                data: { "time": new Date("2015","09","22") },
                cache: false,
                success: function (r) {
                    console.log(r);
                }
            });
        });
复制代码

此时响应信息如下:

{"Message":"请求无效。","MessageDetail":"对于“WebApplication2.Controllers.DefaultController”中方法“System.Net.Http.HttpResponseMessage GetDateTime(System.DateTime)”的不可以为 null 的类型“System.DateTime”的参数“time”,参数字典包含一个 null 项。可选参数必须为引用类型、可以为 null 的类型或声明为可选参数。"}

出错原因是对于简单的参数(如String、Int以及DateTime等)当进行请求时不会进行解析其属性而会将其设置为null,所以传递过来的时间为null,而方法的时间参数又不能为空,所以会出现错误。对于这种情况我们使用特性[FromBody]来解决【注意】当在前台传递值为字符串或者数字时则是可以解析的,能够成功传递到方法的参数时,而利用HttpClient进行传递时则会出现404。

鉴于上述,我们将其方法参数进行如下修饰即可成功

  public HttpResponseMessage GetDateTime([FromBody] DateTime time)

建议

对于前台进行简单参数进行传递以及和利用HttpClient来进行简单参数的传递出现的情况不同,建议在其参数上加上特性 FromBody  ,这样两者皆可避免。

补充

当然有FromBody也就对应的有FromURI,添加此特性就可获得URL上该特性参数对应的值,URI如下:

    var postUrl = "http://localhost:23133/api/default/GetString?message='xpy0928'";

被请求的资源如下:

        [HttpPost]
        public string GetString([FromUri] string message)
        {
            return message;
        }

此时请求时该message对应的值就为xpy0928。

UrlEncoded表单字符串解析

我们在操作表单时肯定会有将表单数据作为字典进行传递的情况,下面我们就来演示这种情况。

如下为Web API需要被请求的方法

复制代码
        [HttpPost]
        public string GetString(string cnblogs)
        {

            return cnblogs;

        }
复制代码

接下来我们利用客户端来访问上述该方法:

复制代码
            var formVars = new Dictionary<string, string>();
            formVars.Add("cnblogs", "xpy0928");
            var content = new FormUrlEncodedContent(formVars);  

            var client = new HttpClient();
            var postUrl = "http://localhost:23133/api/default/GetString";
            var task = client.PostAsync(postUrl, content).Result;  //参数未进行序列化
复制代码

从上述可以看出理论上是可行的,我们通过URI将表单数据以字典形式进行传递去请求Web API,并获取键cnblogs的值。结果会虐死你,如下:

因为这种对于cnblogs参数值映射到方法上的cnblogs参数上在Web API是行不通的,Web API不会进行映射 。

既然简单的参数来接收不行下面我们尝试利用对象来获得该参数的值就像MVC中提交参数到实体上一样。

首先给出一个类,并且该类中含有cnblogs属性,如下:

        public class CnblogsModel
        {
            public string Cnblogs { get; set; }
        }

将其方法及参数修改如下:

复制代码
       [HttpPost]
        public string GetString(CnblogsModel model)
        {

            return model.Cnblogs;

        }
复制代码

接下来就是见证奇迹的时刻到了,给力啊AngelaBaby,皇天不负有心人,如下:

 【注意】由上可知成功的关键是对象中的字段必须要和POST表单中的键必须相匹配,如果有多个键,那么对象中的字段也要与之对应。

上述的解决方案完全是可行的,但是让人忍俊不禁的是这么做似乎有点太操蛋,接受表单中的参数还得建立对象并与之对应,所以得想更好的出路,既然是针对表单的,难道表单中对于接受这样的字典就没有对应的类来进行处理吗,于是乎,开始找啊找,结果找到了一个 FormDataCollection (表面意思是表单数据集合)。貌似可行,来我们继续将其代码进行改写,如下:

复制代码
       [HttpPost]
        public string GetString(FormDataCollection collection)
        {

            return collection.Get("cnblogs");

        }
复制代码

验证通过,如下:

 

这样就比第一个解决方案可行多了,只是对于这样的集合类有点让人想不明白,为什么不直接通过索引来获取数据而非得用对于单个用Get或者对于多个字段用GetValues()方法

你是不是就以为这样简洁就是可行的呢?那你可就错了,当我们在ASP.NET上运行Web API我们完全可以通过如下来进行获取表单数据:

            var request = HttpContext.Current.Request;
            var formKeys = request.Form.AllKeys;

建议

当获取表单数据时建议用 HttpContext.Current.Request  ,虽然它仅仅只能在ASP.NET上进行应用而无法在SelfHost上使用,但是对于一些复杂的场景下,比如说你需要获得一些Web API上的Request没有暴露的数据,此时用此种方法将是不可替代的,同时HttpContext无论是在ASP.NET还是MVC或者Web API中都是存在的。所以尽量避免使用FormDataCollection,即使看起来在路由上使用它更简单。

补充(1)

感谢园友敷衍不起的疑问,刚开始以为挺简单的,结果就是被打脸了,后经过研究对于复杂类型的数据的传递以及接收,若是具体类,利用FormDataCollection是行不通的,我能想到的解决方案是进行如下操作【期待你更好的解决方案】:

复制代码
            var p = new Person() { Name = "person", Student = new Student() { StuName = "xpy0928" } };

            var client = new HttpClient();

            var postUrl = new Uri("http://localhost:23133/api/default/GetString");


            var task = client.PostAsJsonAsync(postUrl, p).Result;  //利用PostAsJsonAsync方法来进行序列化类
复制代码

在Web API上进行接收,如下:

     [HttpPost]
        public string GetString(Person p)
        {
            return p.Name;
        }

至于用FormDataCollection接收不行的原因是 FormUrlEncodedContent 的参数键和值必须都是string类型,若类不是具体类直接添加键和值都是字符串则是可行的,但是这种情况似乎不太现实,所以对于具体类还是利用 PostAsJsonAsync 来进行解决。

补充(2)

感谢园友【YoMekennywangjin】的提醒,上述必须显式通过路由来进行参数传递才会成功,如果通过Request中body来传递就会出现不解析的情况。

访问QueryString 

在命名空间System.Net.Http下有一扩展方法如下:

            var requestUri = Request.RequestUri.ParseQueryString();
            var paramValue = requestUri["param"];

在大多数场景下使用此方法是比较高效的,但是如果在URI中有许多参数,此时你不得不去显式去解析这些参数。

总结

如上述,Web API对于相关参数的映射是比较简单的,但是在一些不同的情况下,你不得不手动做一些工作来进行处理,同时我们也许意识到了Web API并没有提供任何全局上下文对象,例如Request以及过滤中的Formatters等,都是基于Web API来提供特定的方法来进行操作即方法都是为Web API而量身定制,所以在看到Web API强大的同时也要看到其软肋,这样我们才能更好的对于不同场景下作出不同的处理。







本文转自Jeffcky博客园博客,原文链接:http://www.cnblogs.com/CreateMyself/p/4827171.html,如需转载请自行联系原作者
目录
相关文章
|
3月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
63 4
|
3月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
179 3
|
25天前
|
Kubernetes 安全 Devops
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
58 10
有效抵御网络应用及API威胁,聊聊F5 BIG-IP Next Web应用防火墙
|
2月前
|
API
使用京东API接口进行支付结算有哪些注意事项?
使用京东API接口进行支付结算时,需遵守京东开放平台规定,保护用户隐私,关注API接口变化,确保应用合法、完整、可靠,正确使用API对接信息,保持API接口调用成功率,及时整改程序缺陷,结算依据以商家后台系统为准。如需帮助,请私信或评论联系。
|
2月前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
58 1
|
2月前
|
JSON API 数据格式
如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架
本文介绍了如何使用Python和Flask构建一个简单的RESTful API。Flask是一个轻量级的Web框架,适合小型项目和微服务。文章从环境准备、创建基本Flask应用、定义资源和路由、请求和响应处理、错误处理等方面进行了详细说明,并提供了示例代码。通过这些步骤,读者可以快速上手构建自己的RESTful API。
145 2
|
3月前
|
监控 负载均衡 API
Web、RESTful API 在微服务中有哪些作用?
在微服务架构中,Web 和 RESTful API 扮演着至关重要的角色。它们帮助实现服务之间的通信、数据交换和系统的可扩展性。
62 2
|
3月前
|
缓存 监控 API
淘宝API接口注意事项及要点
淘宝API接口的使用需注意以下要点:首先注册并认证开发者账号,获取API密钥;深入理解接口文档,确保参数合法准确;遵守调用频率限制,必要时申请提额;确保数据安全与隐私保护;合理处理错误与异常;优化缓存与性能;关注版本更新与兼容性;遵守合规性与法律要求;建立日志记录与监控机制。
|
3月前
|
移动开发 前端开发 JavaScript
前端开发实战:利用Web Speech API之speechSynthesis实现文字转语音功能
前端开发实战:利用Web Speech API之speechSynthesis实现文字转语音功能
358 0
|
23天前
|
人工智能 自然语言处理 API
Multimodal Live API:谷歌推出新的 AI 接口,支持多模态交互和低延迟实时互动
谷歌推出的Multimodal Live API是一个支持多模态交互、低延迟实时互动的AI接口,能够处理文本、音频和视频输入,提供自然流畅的对话体验,适用于多种应用场景。
69 3
Multimodal Live API:谷歌推出新的 AI 接口,支持多模态交互和低延迟实时互动