事件回放:
之前一段时间,公司里前端用的Angularjs 发送http请求也是用的ng的组件,后台是.Net的WebApi
前端
var data = { PArgs: { PageIndex: 0, PageSize: 8, RowsCount: 0 } }; $http.post("/Api/Test/ABC", data).success(function (data) { console.log(data) });
后台接收
using SignalRDemo.VModel; using System.Web.Http; namespace SignalRDemo.Api { public class TestController : ApiController { [HttpPost] public object ABC([FromBody]MMCourse model) { return model; } } }
具体的Model是这样子的
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; } } }
Model
流程就是后台建好实体类,创建接口
前台指定要访问的接口,传入与后台接收参数的实体类结构相同的对象,后台就能接收到这个数据。运行正常。
后来 某一新建页面 前台没有使用Angularjs,而是用的jQuery,访问同一接口,突然发现 后台接收到的参数一直是null。
WebApi Post方式 怎么会无法获取参数呢?
通过查看控制台的http请求和后台的数据,经过不断的摸索,依次发现几个解决方法,也伴随着一些诡异事件:
方案①
首先 后台肯定是成功接收到了请求的,但是由于某种原因,接口方法的输入参数没有值。
初步判断跟类型转换有关,将接收类型改为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); } })