事件回放:前端
以前一段時間,公司裏前端用的Angularjs 發送http請求也是用的ng的組件,後臺是.Net的WebApiweb
前端ajax
var data = { PArgs: { PageIndex: 0, PageSize: 8, RowsCount: 0 } }; $http.post("/Api/Test/ABC", data).success(function (data) { console.log(data) });
後臺接收json
using SignalRDemo.VModel; using System.Web.Http; namespace SignalRDemo.Api { public class TestController : ApiController { [HttpPost] public object ABC([FromBody]MMCourse model) { return model; } } }
具體的Model是這樣子的api
using System; namespace SignalRDemo.VModel { public class MMCourse : BaseModel { //上傳分頁 public PagerArgs PArgs { set; get; } } public sealed class PagerArgs { /// <summary> /// 分頁 /// </summary> /// <param name="pageIndex">每頁數據條數</param> /// <param name="pageSize">數據總行數</param> public PagerArgs(int pageIndex, int pageSize) { this.PageIndex = pageIndex; this.PageSize = pageSize; } /// <summary> /// 當前頁索引 /// </summary> public int PageIndex { get; set; } /// <summary> /// 每頁數據條數 /// </summary> public int PageSize { get; set; } } }
流程就是後臺建好實體類,建立接口數據結構
前臺指定要訪問的接口,傳入與後臺接收參數的實體類結構相同的對象,後臺就能接收到這個數據。運行正常。app
後來 某一新建頁面 前臺沒有使用Angularjs,而是用的jQuery,訪問同一接口,忽然發現 後臺接收到的參數一直是null。ide
WebApi Post方式 怎麼會沒法獲取參數呢?函數
經過查看控制檯的http請求和後臺的數據,通過不斷的摸索,依次發現幾個解決方法,也伴隨着一些詭異事件:post
方案①
首先 後臺確定是成功接收到了請求的,可是因爲某種緣由,接口方法的輸入參數沒有值。
初步判斷跟類型轉換有關,將接收類型改成JObject,就能收到數據了,而後再序列化->反序列化
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using SignalRDemo.VModel; using System.Web.Http; namespace SignalRDemo.Api { public class TestController : ApiController { [HttpPost] public object ABC([FromBody]JObject model) { return JsonConvert.DeserializeObject<MMCourse>(JsonConvert.SerializeObject(model)); } } }
方案②通過修改參數發現,在不改動後臺的狀況下,若是參數是
var data = { A:1 };
後臺收到的數據結構是這樣的
{ Pargs:{ PageIndex:0, PageSize:0 } }
無論怎樣,數據仍是能傳遞過去,只是webapi將參數轉換的時候應該是出了問題。
回頭仔細看了一下後臺實體類,發現PagerArgs類有一個構造函數 仍是要有兩個參數的。試着添加了一個無參構造,發現數據可以正常獲取了!
這個若是要深究的話 就要研究webapi底層對字符串的反序列化處理了,暫時忽略。
方案③
雖然經過上面兩種方式能夠迂迴解決問題,可是內心還糾結着一個問題:爲毛用Ng的$http.post一直沒事,換了jQuery.post就發生這麼多事?
開始對比兩種方式的請求信息
點擊數據上方的【view source】 查看發送的字符串
ng :
{"PArgs":{"PageIndex":0,"PageSize":8,"RowsCount":0}}
jq:
PArgs%5BPageIndex%5D=0&PArgs%5BPageSize%5D=8&PArgs%5BRowsCount%5D=0
decode以後是
PArgs[PageIndex]=0&PArgs[PageSize]=8&PArgs[RowsCount]=0
ng發送的數據跟預想中是同樣的 跟發送的對象保持一直的json結構。
可是 jq發送的怎麼會成了這種模樣?此外 Request Payload跟Form Data又是什麼?是Content-Type的區別引發的這些麼?
經過查看jq.ajax的Api 找到下面一段
說的就是 若是使用的是post 默認的contentType是「application/x-www-form-urlencoded;charset=UTF-8「,
若是contentType是"..form..",則發送數據的是Form Data 若是是」application/json「 ,則是Request Payload。
而使用這種內容類型時,會把數據用$.param()轉換一次以後再發送。
跟用以前用jq發送的數據內容徹底匹配,就是這個緣由了。
那這樣處理起來就簡單了,只須要發送數據前設置contentType="application/json;charset=UTF-8"就能夠了。
還有一點要注意的是 ajax是不會發送對象的 最終都要轉換成字符串。因此發送的時候須要人爲的處理一下。
var data = { PArgs: { PageIndex: 0, PageSize: 8, RowsCount: 0 } }; $.ajaxSetup({ contentType: "application/json;charset=UTF-8" }) $.post("/Api/Test/ABC", JSON.stringify(data), function (rst) { //TODO }, "json");
或者
$.ajax({ url: "/Api/Test/ABC", dataType: "json", type: "post", contentType: "application/json;charset=UTF-8", data: JSON.stringify(data), success: function (rst) { console.log(rst); } })