.net web api 解决ajax跨站点post请求提交 json 数据问题

本文介绍如何解决 ASP.NET WebAPI 中 AJAX 跨域 POST 请求的问题,包括配置 web.config 允许跨域访问及自定义参数绑定类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

asp.net web api 解决ajax跨站点post请求提交 json 数据问题


一、web api

web api 的 controller ,必须继承 apicontroller:

public class TestController : ApiController

action 可以使用参数绑定直接将 post 请求带的 json 转化为对象,如下:

public string TestMethod([FromBody]PersonInfo pars)

注:要达到这种参数绑定,客户端必须将 设置如下的 content-type 值

Content-Typeapplication/json; charset=utf-8


二、问题

如果客户端设置 content-type 为 application/json ,将导致405 拒绝访问的问题,也就是ajax跨站点请求问题


三、解决方案

1.设置web.config允许跨站点请求

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ...  
  2.     <httpProtocol>  
  3.         <customHeaders>  
  4.             <add name="Access-Control-Allow-Origin" value="*" />  
  5.             <add name="Access-Control-Allow-Methods" value="GET,POST" />  
  6.         </customHeaders>  
  7.     </httpProtocol>  
  8.   </system.webServer>  

2.重写参数绑定类 [FromBody] ,换成自己的 [FromBodyBinder]


四、FromBodyBinder 的实现

[csharp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. </pre></p><pre name="code" class="csharp" style="font-size:14px;">FromBodyBinder 类实现  

[csharp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /// <summary>  
  2. /// web api 动态参数绑定模型  
  3. /// 解决脚本跨域访问问题  
  4. /// </summary>  
  5. public class FromBodyBinder : ParameterBindingAttribute  
  6. {  
  7.     public override System.Web.Http.Controllers.HttpParameterBinding GetBinding(System.Web.Http.Controllers.HttpParameterDescriptor parameter)  
  8.     {  
  9.         return new FromBodyHttpParameterBinding(parameter);  
  10.     }  
  11. }  
  12. public class FromBodyHttpParameterBinding : HttpParameterBinding  
  13. {  
  14.     public FromBodyHttpParameterBinding(HttpParameterDescriptor des)  
  15.         : base(des)  
  16.     {  
  17.         _parsType = des.ParameterType;  
  18.     }  
  19.   
  20.     private Type _parsType;  
  21.     private struct AsyncVoid { }  
  22.     public override Task ExecuteBindingAsync(System.Web.Http.Metadata.ModelMetadataProvider metadataProvider, HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)  
  23.     {  
  24.         //读取post内容  
  25.         var task = actionContext.Request.Content.ReadAsStreamAsync();  
  26.         var content = string.Empty;  
  27.         var sm = task.Result;  
  28.         sm.Seek(0, SeekOrigin.Begin);  
  29.         var bytes = sm.ToByteArray();  
  30.         content = bytes.ToStr(System.Text.Encoding.UTF8);  
  31.         var obj = content.ToJsonDeserialize(_parsType);  
  32.   
  33.         SetValue(actionContext, obj);  
  34.   
  35.         TaskCompletionSource<AsyncVoid> tcs = new TaskCompletionSource<AsyncVoid>();  
  36.         tcs.SetResult(default(AsyncVoid));  
  37.         return tcs.Task;  
  38.     }  
  39. }  

用到一个扩展方法 ToJsonDeserialize(),实现如下

[csharp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public static object ToJsonDeserialize(this string str,Type type)  
  2. {  
  3.     try  
  4.     {  
  5.         if (string.IsNullOrWhiteSpace(str))  
  6.         {  
  7.             return null;  
  8.         }  
  9.         var serialize = new JavaScriptSerializer();  
  10.         //针对日期序列化时区的转化  
  11.         str = Regex.Replace(str, @"\\/Date (?\d+) \\/", match =>  
  12.         {  
  13.             var dt = new DateTime(1970, 1, 1);  
  14.             dt = dt.AddMilliseconds(long.Parse(match.Groups[1].Value));  
  15.             dt = dt.ToLocalTime();  
  16.             return dt.ToString("yyyy-MM-dd HH:mm:ss");  
  17.         });  
  18.         return serialize.Deserialize(str, type);  
  19.     }  
  20.     catch (Exception ex)  
  21.     {  
  22.          
  23.         return null;  
  24.     }  
  25. }  


五、测试代码部分

5.1 服务器代码

[csharp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public class TestController : ApiController  
  2. {  
  3.     public class PersonInfo  
  4.     {  
  5.         public int id { setget; }  
  6.         public string name { setget; }  
  7.         public DateTime create_time { setget; }  
  8.     }  
  9.   
  10.     public string TestMethod([FromBodyBinder]PersonInfo pars)  
  11.     //public string TestMethod([FromBody]PersonInfo pars) web api  的写法  
  12.     {  
  13.         var result = new  
  14.         {  
  15.             receive_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") ,  
  16.             data=pars  
  17.         };  
  18.         return result.ToJsonSerialize();  
  19.     }  
  20. }  

5.2客户端写法

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head>  
  4. <meta charset="UTF-8">  
  5. <title>页面标题</title>  
  6. </head>  
  7. <script src="zepto.js"></script>  
  8.   
  9. <body>  
  10. <input type="button" id="btn" value="type=button" />  
  11.   
  12. </body>  
  13. <script>  
  14.     $(function(){  
  15.         $("#btn").click(function(){  
  16.             var reqdata={  
  17.                 id:"111",  
  18.                 name:"张三",  
  19.                 create_time:"2012-12-12 12:12:12"  
  20.             };  
  21.            var reqdatajson = JSON.stringify(reqdata);  
  22.             alert("请求内容:"+reqdatajson);        
  23.             var url="http://www.xxx.com/Test/TestMethod";  
  24.             $.ajax({                 
  25.                url:url,  
  26.                 data: reqdatajson,  
  27.                 dataType: "json",   
  28.                 type: "POST",  
  29.                 success:function(d){  
  30.                     alert("响应内容:"+JSON.stringify(d))  
  31.                 },  
  32.                 error:function(r,s,m){  
  33.                     console.log(r+"---"+s+"-----------"+m)  
  34.                 }                   
  35.             });  
  36.         });  
  37.     });  
  38.     </script>  
  39. </html>  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值