第二节:如何正确使用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=1234564 /// </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 else16 {17 return "error";18 }19 }20 #endregion21 22 #region 02-用實體接收,加[FromUri]特性23 /// <summary>24 /// Get api/Second/CheckLogin2?userName=admin&pwd=12345625 /// </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 else36 {37 return "error";38 }39 }40 #endregion41 42 #region 03-用實體接收,不加[FromUri]特性43 /// <summary>44 /// Get api/Second/CheckLogin3?userName=admin&pwd=12345645 /// </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 else56 {57 return "error";58 }59 }60 #endregion61 62 #region 04-用dynamic接收,加[FromUri]特性63 /// <summary>64 /// Get api/Second/CheckLogin4?userName=admin&pwd=12345665 /// </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 else76 {77 return "error";78 }79 }80 #endregion81 82 #region 05-沒有任何參數,直接用Request相關方法接收83 /// <summary>84 /// Get api/Second/CheckLogin5?userName=admin&pwd=12345685 /// </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 else98 {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 });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 });?
四. 總結
Put和Delete請求與Post請求的規則相同,另外還有很多極端的情況,不探討了,掌握正確的用法,直接去用最佳用法即可。
總結:記住Get請求和Post請求的標準用法以及基本的調用規則,其他坑爹的情況,可以統統忘記了,注意的是ajax的Get請求,加上一個當前時間或者隨機數的參數,使用HttpClient 等需要禁用緩存。
總結
以上是生活随笔為你收集整理的第二节:如何正确使用WebApi和使用过程中的一些坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一国弃用美元改用人民币,新发货币对标人民
- 下一篇: 5月最新房价数据公布,全国70个大中城市