一. 基礎總結
1.Restful服務改造
Core下的WebApi默認也是Restful格式服務,即通過請求方式(Get,post,put,delete)來區分請求哪個方法,請求的URL中不需要寫方法名。 但是我們不喜歡這種方式,所以我們將默認的路由規則 [Route("api/[controller]")] 改為: [Route("api/[controller]/[action]")]
2.基本格式
繼承 ControllerBase 類,需要加特性[ApiController].
(1) 特性[ApiController]的作用:
a.特性路由要求,和[Route]成對出現,有了它,通過 UseMvc 定義的傳統路由或通過 Startup.Configure 中的 UseMvcWithDefaultRoute 訪問操作均無效。
b.模型驗證錯誤自動觸發 HTTP 400 響應
c.綁定源參數推理(如果沒有 [ApiController] 屬性,同時也沒有 [FromQuery][FromBody]等 的綁定源屬性,ASP.NET Core 運行時會嘗試使用復雜對象模型綁定器。)
d.Multipart/form-data 請求推理
f.錯誤狀態代碼的問題詳細信息
(2) 特性[ApiController]的作用位置:
a.作用於controller
b.作用於程序集,服務於整個項目。在Startup類上的namespace上添加:[assembly: ApiController]
注:它不能作用action上。
PS:MVC中的Controller類繼承ControllerBase類,實現了IActionFilter, IFilterMetadata, IAsyncActionFilter, IDisposable接口。
3.路由規則
詳見 第二十節:Asp.Net Core WebApi和MVC 路由規則比較
4.常見的特性
[Route] 指定控制器或操作的 URL 模式。
[Bind] 指定要包含的前綴和屬性,以進行模型綁定。
[HttpGet] [HttpPost]標識支持 HTTP GET 等操作謂詞的操作。
[Consumes] 指定某個操作接受的數據類型。
[Produces] 指定某個操作返回的數據類型。
5.綁定源參數推理
[FromBody] 實體JSON格式的獲取,和不加效果相同
[FromForm] 請求正文中的表單數據
[FromQuery] 請求查詢字符串參數,Get請求的時候,用實體接受需要加
[FromHeader] 請求標頭
[FromRoute] 當前請求中的路由數據
[FromServices] 作為操作參數插入的請求服務,即將對象注入到方法中
6.允許跨域
同Core MVC相同,詳見:https://www.cnblogs.com/yaopengfei/p/11191938.html
7.過濾器
同Core MVC相同,詳見:https://www.cnblogs.com/yaopengfei/p/11232921.html, 但webapi中頁面相關的過濾器不適用
二. Get和Post請求
1. Get請求
前端JS發送Get請求的時候,后台可以分參數接收,也可以用實體接收,但是需要在實體的前面加上[FromQuery]。
注:不能用dynamic接收,不管怎么處理都報錯。
案例測試:
(1).分參數接收,可以正常訪問。
(2).用實體類接收,前面加[FromQuery],可以正常訪問(否則報415)。
(3).用dynamic接收,前面什么不加,報錯415,前面加[FromQuery],也報錯,報500。
服務器端代碼:
1 [Route("api/[controller]/[action]")] 2 [ApiController] 3 public class FirstController : ControllerBase 4 { 5 /******************************************下面是測試Get請求的相關方法***************************************************/ 6 7 [HttpGet] 8 public string GetInfor1(string userName, string pwd) 9 { 10 return $"{userName}+{pwd}"; 11 } 12 13 [HttpGet] 14 public string GetInfor2([FromQuery]UserInfor model) 15 { 16 return $"{model.userName}+{model.pwd}"; 17 } 18 [HttpGet] 19 //加上[FromQuery]也報錯 20 public string GetInfor3([FromQuery]dynamic model) 21 { 22 return $"{model.userName}+{model.pwd}"; 23 } 24 25 }
前端代碼:
1 //一.下面是Get請求的測試 2 //1. 分參數接收,可以正常訪問 3 $("#getBtn1").click(function () { 4 $.ajax({ url: "https://localhost:44387/api/First/GetInfor1", type: "get", data: { userName: "admin", pwd: "123456" }, success: function (data) { console.log(data); } }); 5 }); 6 //2. 用實體類接收,前面加[FromQuery],可以正常訪問(否則報415) 7 $("#getBtn2").click(function () { 8 $.ajax({ url: "https://localhost:44387/api/First/GetInfor2", type: "get", data: { userName: "admin", pwd: "123456" }, success: function (data) { console.log(data); } }); 9 }); 10 //3. 用dynamic接收,前面什么不加,報錯415,前面加[FromQuery],也報錯,報500 11 $("#getBtn3").click(function () { 12 $.ajax({ url: "https://localhost:44387/api/First/GetInfor3", type: "get", data: { userName: "admin", pwd: "123456" }, success: function (data) { console.log(data); } });
2. Post請求
前端JS發送Post請求的時候,可能是表單提交,也可能是JOSN格式提交,所以下面要分情況討論:默認情況下在我們注入MVC服務時被配置使用的時JsonInputFormatter,即實體默認接受JSON格式的數據,我們如果想讓它接受表單數據,需要在實體前面加[FromForm].
(1) 接收JSON格式:實體前面什么也不加 或者 實體前面加[FromBody]
(2) 接收表單格式: 實體前面加[FromForm]
注:不能分參數接收!! 用dynamic接收的時候,只能處理前端JOSN格式的數據,加[FromBody]或者不加都行, 不能處理前端表單格式數據!!
案例測試:
(1).一個參數的情況,后台分參數接收,均拿不到值
(2).表單提交,實體前面什么也不加 或者 實體前面加[FromForm],Login1 和 Login2 均報415,Login3可以正常訪問
(3).JSON提交,實體前面加[FromBody],Login1,Login2正常訪問,Login3能訪問通,但是后台拿不到值,都為空
(4).JOSN格式,后台用dynamic能接收,加[FromBody]或者不加都可以接收
(5).表單格式,后台用dynamic不能接收,加[FromForm]或者不加都報500,報錯。
服務器端代碼:
1 [Route("api/[controller]/[action]")] 2 [ApiController] 3 public class FirstController : ControllerBase 4 { 5 6 /******************************************下面是測試Post請求的相關方法***************************************************/ 7 8 [HttpPost] 9 public string Login0(string userName) 10 { 11 return $"{userName}"; 12 } 13 14 [HttpPost] 15 public string Login1(UserInfor model) 16 { 17 return $"{model.userName}+{model.pwd}"; 18 } 19 20 [HttpPost] 21 public string Login2([FromBody]UserInfor model) 22 { 23 return $"{model.userName}+{model.pwd}"; 24 } 25 26 [HttpPost] 27 public string Login3([FromForm]UserInfor model) 28 { 29 return $"{model.userName}+{model.pwd}"; 30 } 31 [HttpPost] 32 public string Login4([FromBody]dynamic model) 33 { 34 return $"{model.userName}+{model.pwd}"; 35 } 36 37 [HttpPost] 38 public string Login5([FromForm]dynamic model) 39 { 40 return $"{model.userName}+{model.pwd}"; 41 } 42 }
前端代碼:
1 //二.下面是Post請求的測試 2 //(Post請求默認情況下為:ContentType = "application/x-www-form-urlencoded"提交表單的形式,如果要發送JOSN格式,需要加上參數contentType: 'application/json') 3 //PS: { userName: "admin", pwd: "123456" } 這就是一個JSON對象,也可以叫實體 4 5 //1. 一個參數的情況,后台分參數接收,均拿不到值 6 $("#postBtn0").click(function () { 7 //1.1 正常拼接,可以訪問通,但是拿不到userName的值 8 //$.ajax({ url: "https://localhost:44387/api/First/Login0", type: "Post", data: { userName: "admin" }, success: function (data) { console.log(data); } }); 9 //1.2 沒有鍵,只有值,可以訪問通,但是拿不到userName的值 (這里同.Net 平台下的WebApi不同) 10 $.ajax({ url: "https://localhost:44387/api/First/Login0", type: "Post", data: { "": "admin" }, success: function (data) { console.log(data); } }); 11 }); 12 13 //2. 表單提交,Login1 和 Login2 均報415,Login3可以正常訪問 14 $("#postBtn1").click(function () { 15 $.ajax({ url: "https://localhost:44387/api/First/Login1", type: "Post", data: { userName: "admin", pwd: "123456" }, success: function (data) { console.log("Login1:" + data); } }); 16 $.ajax({ url: "https://localhost:44387/api/First/Login2", type: "Post", data: { userName: "admin", pwd: "123456" }, success: function (data) { console.log("Login2:" + data); } }); 17 $.ajax({ url: "https://localhost:44387/api/First/Login3", type: "Post", data: { userName: "admin", pwd: "123456" }, success: function (data) { console.log("Login3:" + data); } }); 18 }); 19 20 //3.JSON提交,Login1,Login2正常訪問,Login3能訪問通,但是后台拿不到值,都為空 21 $("#postBtn2").click(function () { 22 //將post請求指定為contentType: 'application/json',且傳遞的參數格式化成Json字符串,則可以正常訪問 23 $.ajax({ url: "https://localhost:44387/api/First/Login1", type: "Post", contentType: 'application/json', data: JSON.stringify({ userName: "admin", pwd: "123456" }), success: function (data) { console.log("Login1:" + data); } }); 24 $.ajax({ url: "https://localhost:44387/api/First/Login2", type: "Post", contentType: 'application/json', data: JSON.stringify({ userName: "admin", pwd: "123456" }), success: function (data) { console.log("Login2:" + data); } }); 25 $.ajax({ url: "https://localhost:44387/api/First/Login3", type: "Post", contentType: 'application/json', data: JSON.stringify({ userName: "admin", pwd: "123456" }), success: function (data) { console.log("Login3:" + data); } }); 26 27 }); 28 29 //4.JOSN格式,后台用dynamic能接收,加[FromBody]或者不加都可以接收 30 $("#postBtn3").click(function () { 31 //將post請求指定為contentType: 'application/json',且傳遞的參數格式化成Json字符串,則可以正常訪問 32 $.ajax({ url: "https://localhost:44387/api/First/Login4", type: "Post", contentType: 'application/json', data: JSON.stringify({ userName: "admin", pwd: "123456" }), success: function (data) { console.log("JSON:" + data); } }); 33 }); 34 //5.表單格式,后台用dynamic不能接收,加[FromForm]或者不加都報500 35 $("#postBtn4").click(function () { 36 $.ajax({ url: "https://localhost:44387/api/First/Login5", type: "Post", data: { userName: "admin", pwd: "123456" }, success: function (data) { console.log("表單:" + data); } }); 37 });
3.總結
Get請求,可以分參數接收,也可以用實體接收,需要在實體的前面加上[FromQuery]。
POST請求,用實體接收,針對js默認的表單提交方式,實體前面加[FromForm];針對js的JSON格式的提交方式,實體前面什么也不加 或者 實體前面加[FromBody]。
4. 返回值的問題(補充)
用Content標記json類型和直接返回序列化字符串的區別。用 Content(jsonData, "application/json"); 標記,前端什么不用加,可以直接點出來的。
/// <summary> /// 前端不能直接點出來 /// </summary> /// <returns></returns> [HttpGet] public string GetGoodById1() { var myData = new { status = "ok", goods = new UserInfor() { userName = "apple", pwd = "12345" } }; var jsonData = JsonConvert.SerializeObject(myData); return jsonData; } /// <summary> /// 前端可以直接 點出來 /// </summary> /// <returns></returns> [HttpGet] public IActionResult GetGoodById2() { var myData = new { status = "ok", goods = new UserInfor() { userName = "apple", pwd = "12345" } }; var jsonData = JsonConvert.SerializeObject(myData); return Content(jsonData, "application/json"); }
前端調用
$("#rBtn1").click(function () { $.ajax({ url: "https://localhost:44387/api/First/GetGoodById1", type: "get", data: { userName: "admin", pwd: "123456" }, success: function (data) { console.log(data); //不能直接點出來 console.log(data.status); } }); $.ajax({ url: "https://localhost:44387/api/First/GetGoodById1", type: "get", data: { userName: "admin", pwd: "123456" }, dataType: "json", success: function (data) { console.log(data); //加上dataType: "json",就能直接點出來 console.log(data.status); } }); }); $("#rBtn2").click(function () { $.ajax({ url: "https://localhost:44387/api/First/GetGoodById2", type: "get", data: { userName: "admin", pwd: "123456" }, success: function (data) { console.log(data); //能直接點出來 console.log(data.status); } }); });
!
- 作 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 本人才疏學淺,用郭德綱的話說“我是一個小學生”,如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。