一. 基本调用规则

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 == "")
  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 == "")
  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 == "")
  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 == "")
  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 == "")
  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 == "")
  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 == "")
  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 == "")
  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 == "")
  68. {
  69. return "ok";
  70. }
  71. else
  72. {
  73. return "error";
  74. }
  75. }
  76. #endregion
  77.  
  78. }

服务器端代码

  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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 

第二节:如何正确使用WebApi和使用过程中的一些坑的更多相关文章

  1. 关于webapi练习过程中遇到的一系列问题记录

    最近在尝试本地进行webapi调用的过程中,遇到一系列的问题,demo很小但着实让人头疼,先附上demo. 前台页面,目的是展示新闻的分类: 类别模型如下: 控制器代码如下: public Actio ...

  2. 【精编重制版】JavaWeb 入门级项目实战 -- 文章发布系统 (第二节)

    说明 本教程是,原文章发布系统教程的精编重制版,会包含每一节的源码,以及修正之前的一些错误.因为之前的教程只做到了评论模块,很多地方还不完美,因此重制版会修复之前的一些谬误和阐述不清的地方,而且,后期 ...

  3. delphi 线程教学第二节:在线程时空中操作界面(UI)

    第二节:在线程时空中操作界面(UI)   1.为什么要用 TThread ?   TThread 基于操作系统的线程函数封装,隐藏了诸多繁琐的细节. 适合于大部分情况多线程任务的实现.这个理由足够了吧 ...

  4. CUDA:Supercomputing for the Masses (用于大量数据的超级计算)-第二节

    原文链接 第二节:第一个内核 Rob Farber 是西北太平洋国家实验室(Pacific Northwest National Laboratory)的高级科研人员.他在多个国家级的实验室进行大型并 ...

  5. android内部培训视频_第二节 布局基础

    第二节:布局入门 一.线性布局 需要掌握的属性: 1.orientation:排列方式 vertical:垂直 Horizontal:水平 2.weight:水平布局的权重 3.gravity:子控件 ...

  6. 第二节:AppDomain

    CLR COM服务器初始化时,会创建一个AppDomain.AppDomain是一组程序集的逻辑容器.CLR初始化时创建的第一个AppDomain称为默认的AppDomain,这个默认的AppDoma ...

  7. seajs第二节,seajs各模块依赖关系

    index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> &l ...

  8. 学习javascript基础知识系列第二节 - this用法

    通过一段代码学习javascript基础知识系列 第二节 - this用法 this是面向对象语言中的一个重要概念,在JAVA,C#等大型语言中,this固定指向运行时的当前对象.但是在javascr ...

  9. VUE2.0实现购物车和地址选配功能学习第二节

    第二节 创建VUE实例 购物车项目计划: 1.创建一个vue实例 2.通过v-for指令渲染产品数据 3.使用filter对金额和图片进行格式化 4.使用v-on实现产品金额动态计算 5.综合演示 ① ...

随机推荐

  1. 我认知的javascript之作用域和闭包

    说到javascript,就不得不说javascript的作用域和闭包:当然,还是那句老话,javascript在网上都说得很透彻了,我也就不过多的强调了: 作用域:javascript并没有像其他的 ...

  2. Tmux 入门

    什么是 Tmux Tmux 官方 Wiki 简单来说,Tmux 是一个能够让你一个窗口当多个窗口使用的终端模拟器.并且你还可以将它放到后台,等到想使用的时候再使用. 为什么要用 Tmux 在服务器上调 ...

  3. MySQL 数据库的创建&修改

    -- 创建数据库 CREATE DATABASE [IF NOT EXISTS]<数据库名> DEFAULT CHARACTER SET utf8; -- 默认字符集为utf8 -- 指定 ...

  4. Redis操作集合,有序集合

    Set操作,Set集合就是不允许重复的列表 sadd(name,values) 1 # name对应的集合中添加元素 scard(name) 1 获取name对应的集合中元素个数 sdiff(keys ...

  5. C#基础知识之关键字

    关键字是 C# 编译器预定义的保留字.这些关键字不能用作标识符,但是,如果您想使用这些关键字作为标识符,可以在关键字前面加上 @ 字符作为前缀.在 C# 中,有些关键字在代码的上下文中有特殊的意义,如 ...

  6. 【转】Vue.js中 watch 的高级用法

    假设有如下代码: <div> <p>FullName: {{fullName}}</p> <p>FirstName: <input type=&q ...

  7. luogu P4842 城市旅行

    嘟嘟嘟 好题,好题 刚开始突发奇想写了一个\(O(n ^ 2)\)暴力,结果竟然过了?!后来才知道是上传题的人把单个数据点开成了10s-- 不过不得不说我这暴力写的挺好看的.删边模仿链表删边,加边的时 ...

  8. mysql中group by和order by混用 结果不是理想结果(转)

    文章转自 https://www.cnblogs.com/myphper/p/3767572.html 在使用mysql排序的时候会想到按照降序分组来获得一组数据,而使用order by往往得到的不是 ...

  9. (九)Delete an Index

    Now let’s delete the index that we just created and then list all the indexes again: 现在让我们删除刚刚创建的索引, ...

  10. node+mysql 数据库连接池

    1. 什么是数据库连接池? 数据库连接池是程序启动时建立足够的数据库连接,并将这些连接组成一个池,由程序动态地对池中的连接进行申请,使用和释放. 2. 使用数据库连接池原理及优点是什么? 数据库连接池 ...