zoukankan      html  css  js  c++  java
  • 第二节:如何正确使用WebApi和使用过程中的一些坑

    一. 基本调用规则

    1. 前提

      WebApi的默认路由规则为:routeTemplate: "api/{controller}/{id}", 下面为我们统一将它改为 routeTemplate: "api/{controller}/{action}/{id}",这样我们在调用的时候,还是通过拼接方法名来识别,不用考虑上面的坑别的规则了,这里我单纯的来探讨WebApi的传参和调用。

    2. 基本的调用规则

      是什么请求,在方法上面标注什么特性,常见的有[HttpGet][HttpPost][HttpPut][HttpDelete]。

    PS:方法名以Get、Post、Put、Delete开头,WebApi会自动默认这个请求就是Get、Post、Put、Delete请求,而如果你以其他名称开头而又不标注方法的请求方式,那么这个时候服务器虽然找到了这个方法,但是由于请求方式不确定,所以直接返回给你405——方法不被允许的错误。

    二. Get请求规则

    1. 标准用法:

      发起请求的方式都为 api/Second/CheckLogin?userName=admin&pwd=123456 这种类型,不管几个参数(1个或多个),接收的时候,如果是分参数接收,没有任何问题, 可以正常接收,但如果是通过实体类来接收,必须在前面加特性[FromUri],否则接收不到。

    PS:当然也可以什么参数都不写,通过传统的Request或者Request.QueryString来接受。

    2. 实战测试:

    (1). 分别调用CheckLogin1、CheckLogin2、CheckLogin3方法, 发现前两个方法都能正常调用,CheckLogin3这个方法报错, 报:"Message":"出现错误","ExceptionMessage":"未将对象引用设置到对象的实例"。

    (2). 调用CheckLogin4方法,报与上面相同的错误,证明dynamic类型也不能这么用。

    (3). 调用CheckLogin5方法,能正常接收,表明可以通过传统的Request或者Request.QueryString来接受。

    代码分享:

    1   public class LoginModel
    2     {
    3         public string userName { get; set; }
    4 
    5         public string pwd { get; set; }
    6     }
    实体类
      1         #region 01-分参数接收
      2         /// <summary>
      3         /// Get api/Second/CheckLogin1?userName=admin&pwd=123456
      4         /// </summary>
      5         /// <param name="userName"></param>
      6         /// <param name="pwd"></param>
      7         /// <returns></returns>
      8         [HttpGet]
      9         public string CheckLogin1(string userName, string pwd)
     10         {
     11             if (userName == "admin" && pwd == "123456")
     12             {
     13                 return "ok";
     14             }
     15             else
     16             {
     17                 return "error";
     18             }
     19         }
     20         #endregion
     21 
     22         #region 02-用实体接收,加[FromUri]特性
     23         /// <summary>
     24         /// Get api/Second/CheckLogin2?userName=admin&pwd=123456
     25         /// </summary>
     26         /// <param name="model"></param>
     27         /// <returns></returns>
     28         [HttpGet]
     29         public string CheckLogin2([FromUri]LoginModel model)
     30         {
     31             if (model.userName == "admin" && model.pwd == "123456")
     32             {
     33                 return "ok";
     34             }
     35             else
     36             {
     37                 return "error";
     38             }
     39         }
     40         #endregion
     41 
     42         #region 03-用实体接收,不加[FromUri]特性
     43         /// <summary>
     44         /// Get api/Second/CheckLogin3?userName=admin&pwd=123456
     45         /// </summary>
     46         /// <param name="model"></param>
     47         /// <returns></returns>
     48         [HttpGet]
     49         public string CheckLogin3(LoginModel model)
     50         {
     51             if (model.userName == "admin" && model.pwd == "123456")
     52             {
     53                 return "ok";
     54             }
     55             else
     56             {
     57                 return "error";
     58             }
     59         }
     60         #endregion
     61 
     62         #region 04-用dynamic接收,加[FromUri]特性
     63         /// <summary>
     64         /// Get api/Second/CheckLogin4?userName=admin&pwd=123456
     65         /// </summary>
     66         /// <param name="model"></param>
     67         /// <returns></returns>
     68         [HttpGet]
     69         public string CheckLogin4([FromUri]dynamic model)
     70         {
     71             if (model.userName == "admin" && model.pwd == "123456")
     72             {
     73                 return "ok";
     74             }
     75             else
     76             {
     77                 return "error";
     78             }
     79         }
     80         #endregion
     81 
     82         #region 05-没有任何参数,直接用Request相关方法接收
     83         /// <summary>
     84         /// Get api/Second/CheckLogin5?userName=admin&pwd=123456
     85         /// </summary>
     86         /// <param name="model"></param>
     87         /// <returns></returns>
     88         [HttpGet]
     89         public string CheckLogin5()
     90         {
     91             var userName = HttpContext.Current.Request["userName"];
     92             var pwd = HttpContext.Current.Request.QueryString["pwd"];
     93             if (userName == "admin" && pwd == "123456")
     94             {
     95                 return "ok";
     96             }
     97             else
     98             {
     99                 return "error";
    100             }
    101         }
    102         #endregion
    服务器端代码
     1   //一.下面是Get请求的测试
     2             //1. 分参数接收,可以正常访问
     3             $("#getBtn1").click(function () {
     4                 $.ajax({ url: "/api/Second/CheckLogin1", type: "get", data: { userName: "admin", pwd: "123456" }, success: function (data) { alert(data); } });
     5             });
     6             //2. 用实体类接收,前面加[FromUrl],可以正常访问
     7             $("#getBtn2").click(function () {
     8                 $.ajax({ url: "/api/Second/CheckLogin2", type: "get", data: { userName: "admin", pwd: "123456" }, success: function (data) { alert(data); } });
     9             });
    10             //3. 用实体类接收,前面什么不加,报错
    11             // "Message":"出现错误","ExceptionMessage":"未将对象引用设置到对象的实例"
    12             $("#getBtn3").click(function () {
    13                 $.ajax({ url: "/api/Second/CheckLogin3", type: "get", data: { userName: "admin", pwd: "123456" }, success: function (data) { alert(data); } });
    14             });
    15             //4. 用dynamic接收,前面什么不加,报错
    16             // "Message":"出现错误","ExceptionMessage":"未将对象引用设置到对象的实例"
    17             $("#getBtn4").click(function () {
    18                 $.ajax({ url: "/api/Second/CheckLogin4", type: "get", data: { userName: "admin", pwd: "123456" }, success: function (data) { alert(data); } });
    19             });
    20             //5. 后台直接用Request或者Request.QueryString,能正常接收
    21             $("#getBtn5").click(function () {
    22                 $.ajax({ url: "/api/Second/CheckLogin5", type: "get", data: { userName: "admin", pwd: "123456" }, success: function (data) { alert(data); } });
    23             });
    前端JS代码

    3. 特别说明:

      建议忘掉实战测试中的几种错误情况,记住标准用法即可。

    三. Post请求规则

    1.标准用法:

      参数一定要用“实体类”接收(即使一个参数也要封装实体类),客户端既可以用ContentType="application/x-www-form-urlencoded"提交表单,也可以用 ContentType ="application/json"提交, 模型类前面可以加[FromBody],但只能在一个参数前面加.

    2.实战测试

    (1). 当只有一个参数的情况,且加[FromBody]特性,不封装实体,如Register0,正常的键值对 { userName: "admin" }能访问通,但后台拿不到值,只有省掉键名{ "": "admin" },才能正常访问,且后台能拿到值。

    (2). 多个参数的情况,后台分参数接收,如Register1,正常的键值对提交,无法访问,提示找不到匹配的资源。

    (3). 一个或多个参数的情况,后台用实体接收,如Register2,且加[FromBody]特性,可以正常访问,并获取到请求值。

      ①:默认的post请求,即ContentType="application/x-www-form-urlencoded"的形式,可以正常请求。

      ②:将post请求指定为contentType: 'application/json',且传递的实体格式化成Json字符串,则可以正常请求。

    (4). 一个或多个参数的情况,后台用dynamic接收,且加[FromBody]特性,需要分情况讨论。

      ①:默认的post请求,即ContentType="application/x-www-form-urlencoded"的形式,服务器报500错误。

      ②:将post请求指定为contentType: 'application/json',且传递的实体格式化成Json字符串,则可以正常请求。

    阶段总结:后台用实体接收和用dynamic类型接收,用实体接收,无论是"application/x-www-form-urlencoded"还是"application/json"都能访问;如果用dynamic类型接收,只有"application/json"能访问, 且参数必须是序列化后的字符串

    (5). 一个或多个参数的情况,没有参数,如Register4,通过Request或者Request.Form相关方法可以获取请求值。

     代码分享:

     1  #region 01-单个参数,加[FromBody]特性
     2         [HttpPost]
     3         public string Register0([FromBody]string userName)
     4         {
     5             if (userName == "admin")
     6             {
     7                 return "ok";
     8             }
     9             else
    10             {
    11                 return "error";
    12             }
    13         }
    14         #endregion
    15 
    16         #region 02-多个参数,分参数接收
    17         [HttpPost]
    18         public string Register1(string userName, string pwd)
    19         {
    20             if (userName == "admin" && pwd == "123456")
    21             {
    22                 return "ok";
    23             }
    24             else
    25             {
    26                 return "error";
    27             }
    28         }
    29         #endregion
    30 
    31         #region 03-用实体接收,加[FromBody]特性
    32         [HttpPost]
    33         public string Register2([FromBody]LoginModel model)
    34         {
    35             if (model.userName == "admin" && model.pwd == "123456")
    36             {
    37                 return "ok";
    38             }
    39             else
    40             {
    41                 return "error";
    42             }
    43         }
    44         #endregion
    45 
    46         #region 04-用dynamic接收,加[FromBody]特性
    47         [HttpPost]
    48         public string Register3([FromBody]dynamic model)
    49         {
    50             if (model.userName == "admin" && model.pwd == "123456")
    51             {
    52                 return "ok";
    53             }
    54             else
    55             {
    56                 return "error";
    57             }
    58         }
    59         #endregion
    60 
    61         #region 05-没有任何参数,直接用Request相关方法接收
    62         [HttpPost]
    63         public string Register4()
    64         {
    65             var userName = HttpContext.Current.Request["userName"];
    66             var pwd = HttpContext.Current.Request.Form["pwd"];
    67             if (userName == "admin" && pwd == "123456")
    68             {
    69                 return "ok";
    70             }
    71             else
    72             {
    73                 return "error";
    74             }
    75         } 
    76         #endregion
    77 
    78 
    79     }
    服务器端代码
     1  //二.下面是Post请求的测试(默认情况下为:ContentType="application/x-www-form-urlencoded"提交表单的形式)
     2             //PS: { userName: "admin", pwd: "123456" } 这就是一个JSON对象,也可以叫实体
     3 
     4             //1. 一个参数的情况,后台分参数接收,且必须加[FromBody]特性
     5             $("#postBtn0").click(function () {
     6                 //1.1 正常拼接,可以访问通,但是拿不到userName的值
     7                 $.ajax({ url: "/api/Second/Register0", type: "Post", data: { userName: "admin" }, success: function (data) { alert(data); } });
     8                 //1.2 没有键,只有值,可以正常访问,能拿到userName的值
     9                 //$.ajax({ url: "/api/Second/Register0", type: "Post", data: { "": "admin" }, success: function (data) { alert(data); } });
    10             });
    11             //2. 多个参数的情况,后台分参数接收,正常的键值对提交,无法访问,找不到匹配的资源
    12             $("#postBtn1").click(function () {
    13                 //访问不通
    14                 $.ajax({ url: "/api/Second/Register1", type: "Post", data: { userName: "admin", pwd: "123456" }, success: function (data) { alert(data); } });
    15             });
    16             //3. 一个或多个参数的情况,后台用实体接收,且加[FromBody]特性,可以正常访问,并获取到请求值
    17             $("#postBtn2").click(function () {
    18                 //情况①,默认的post请求,即ContentType="application/x-www-form-urlencoded"的形式,可以正常请求
    19                 //$.ajax({ url: "/api/Second/Register2", type: "Post", data: { userName: "admin", pwd: "123456" }, success: function (data) { alert(data); } });
    20 
    21                 //情况②,将post请求指定为contentType: 'application/json',且传递的参数格式化成Json字符串,则可以正常访问
    22                 $.ajax({ url: "/api/Second/Register2", type: "Post", contentType: 'application/json', data: JSON.stringify({ userName: "admin", pwd: "123456" }), success: function (data) { alert(data); } });
    23 
    24             });
    25             //4. 一个或多个参数的情况,后台用dynamic接收,且加[FromBody]特性,需要分情况讨论
    26             $("#postBtn3").click(function () {
    27                 //情况①,默认的post请求,即ContentType="application/x-www-form-urlencoded"的形式,服务器报500错误
    28                 //$.ajax({ url: "/api/Second/Register3", type: "Post", data: { userName: "admin", pwd: "123456" }, success: function (data) { alert(data); } });
    29 
    30                 //情况②,将post请求指定为contentType: 'application/json',且传递的参数格式化成Json字符串,则可以正常访问
    31                 $.ajax({ url: "/api/Second/Register3", type: "Post", contentType: 'application/json', data: JSON.stringify({ userName: "admin", pwd: "123456" }), success: function (data) { alert(data); } });
    32             });
    33             //5. 一个或多个参数的情况,没有参数,通过Request或者Request.Form相关方法可以获取请求值
    34             $("#postBtn4").click(function () {
    35                 //访问不通
    36                 $.ajax({ url: "/api/Second/Register4", type: "Post", data: { userName: "admin", pwd: "123456" }, success: function (data) { alert(data); } });
    37             });
    前端JS代码

    四. 总结

      Put和Delete请求与Post请求的规则相同,另外还有很多极端的情况,不探讨了,掌握正确的用法,直接去用最佳用法即可。

      总结:记住Get请求和Post请求的标准用法以及基本的调用规则,其他坑爹的情况,可以统统忘记了,注意的是ajax的Get请求,加上一个当前时间或者随机数的参数,使用HttpClient 等需要禁用缓存。

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    生成二维码
    【C#】教你纯手工用C#实现SSH协议作为GIT服务端
    Git断点续传和离线增量更新的实现
    微信定位真的泄露了你的精确位置
    Helper Files
    正则表达式的一些应用
    Apache配置SSL实现HTTP转HTTPS及可能出现的问题(配置https启动不了的解决办法)
    Python3 采集APP数据及相关配置
    Laravel 5 中间件、路由群组、子域名路由、 权限控制的基本使用方法
    Python3使用cookielib模块
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/10273118.html
Copyright © 2011-2022 走看看