.net web api 解決ajax跨站點post請求提交 json 數據問題

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-Type application/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>  

發佈了22 篇原創文章 · 獲贊 18 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章