web api 二
接著上一回說,上回說到,web api有幾種訪問方式,具體有幾種,我還真沒去研究過,但是這里打算從get、post、put、delete四種請求方式分別談談基礎類型(包括int/string/datetime等)、實體、數組等類型的參數如何傳遞。
在介紹之前,有個概念必須先弄清楚:出于安全考慮,瀏覽器會限制腳本中發起的跨站請求,瀏覽器要求JavaScript或Cookie只能訪問同域下的內容。?
什么意思,就拿現在做的這個來說,在這里,我是把webapi項目作為一個單獨的控制層來處理,而MVC項目就是表示層,model項目就是數據層了?,F在我需要在表示層通過js來調用控制層的函數來獲取數據層的數據,這里的調用方式就是webapi的調用方式。那么問題就來了,因為是不同的項目,表示層和控制層的端口不一樣的,表示層的是7866,控制層的是6972,它們之間的請求就是跨站請求,偏偏瀏覽器是限制的(這里要說明一下,IE10,IE11在不作任何處理的情況下可以跨站請求,其他瀏覽器不行,這可能是微軟開后門了),所以就有了webapi的跨域這個概念。
跨域問題的解決:
CORS全稱Cross-Origin Resource Sharing,中文全稱跨域資源共享。它解決跨域問題的原理是通過向http的請求報文和響應報文里面加入相應的標識告訴瀏覽器它能訪問哪些域名的請求。比如我們向響應報文里面增加這個Access-Control-Allow-Origin:http://localhost:6972,就表示支持http://localhost:6972里面的所有請求訪問系統資源。其他更多的應用我們就不一一列舉,可以去網上找找。
首先是在api項目中建一個類:
public class CrossSiteAttribute : System.Web.Http.Filters.ActionFilterAttribute{private const string Origin = "Origin";/// <summary>/// Access-Control-Allow-Origin是HTML5中定義的一種服務器端返回Response header,用來解決資源(比如字體)的跨域權限問題。/// </summary>private const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";/// <summary>/// originHeaderdefault的值可以使 URL 或 *,如果是 URL 則只會允許來自該 URL 的請求,* 則允許任何域的請求/// </summary>private const string originHeaderdefault = "http://localhost:7866";/// <summary>/// 該方法允許api支持跨域調用/// </summary>/// <param name="actionExecutedContext"> 初始化 System.Web.Http.Filters.HttpActionExecutedContext 類的新實例。</param>public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext){actionExecutedContext.Response.Headers.Add(AccessControlAllowOrigin, originHeaderdefault);}}里面的http://localhost:7866就是mvc項目的地址。
?還有一只方式允許所有網站都可跨域來訪問當前項目里的資源,就是在web.config中添加如下代碼。
<system.webServer><validation validateIntegratedModeConfiguration="false"/><handlers><remove name="ExtensionlessUrlHandler-Integrated-4.0"/><remove name="OPTIONSVerbHandler"/><remove name="TRACEVerbHandler"/><add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0"/></handlers></system.webServer>?
一、get請求
對于取數據,我們使用最多的應該就是get請求了吧,上回的例子中就有用到,在這里再來介紹一下
對于get請求,有前端和后端兩種方式,前端就是用js來實現,后端就是上回說的那樣。首先看前端請求。
1、調用無參函數,返回字符串
上面分別是視圖項目和控制項目的相關代碼,運行結果如下。在api項目中對兩個函數添加了?[CrossSite]約束,當然也可以將這個約束添加到valuescontroller上,這樣就對所有函數都約束了
?
2、調用有參函數,返回字符串
function btn2() {$.ajax({type: 'get',url: "http://localhost:6972/api/values/getString",data: {txt:'123456'},traditional: true,async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}?
3、調用多參函數返回字符串
function btn3() {$.ajax({type: 'get',url: "http://localhost:6972/api/values/GetAllChargingData",data: { id: 1234, name: "ffff", dt: "1988-09-11" },traditional: true,async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}public string GetAllChargingData(int id, string name,DateTime dt){return name+"-" + id+"-"+dt.ToString();}4、將實體傳入后臺調用,并返回一個字符串
function btn4() {$.ajax({type: 'get',url: "http://localhost:6972/api/values/GetSiteName",contentType: "application/json",data: { query: JSON.stringify({ SiteId: 1, Title: "fwwe", Uri: "rwerwerwe" }) },//將實體序列化traditional: true,async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}public string GetSiteName(string query){Site obj = Newtonsoft.Json.JsonConvert.DeserializeObject<Site>(query);//反序列化return "名稱:" + obj.Title;}5、返回實體
function btn5() {$.ajax({type: 'get',url: "http://localhost:6972/api/values/GetSiteByID",data: { id: 2},traditional: true,async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data.Title);}else {$.ligerDialog.alert("", "操作失敗", "error");}}}); }public Site GetSiteByID(int id){SiteSource ss = new SiteSource();return ss.DateSource().Where(o => o.SiteId == id).FirstOrDefault();}后端請求:
6、返回實體
public JsonResult getSiteById(int id){HttpClient httpClient = new HttpClient();//GET方式去調用webapivar responseJson = httpClient.GetAsync("http://localhost:6972/api/values/GetSiteByID?id="+id).Result.Content.ReadAsStringAsync().Result;Site site = JsonConvert.DeserializeObject<Site>(responseJson);//允許使用GET方式獲取,否則用GET獲取是會報錯return new JsonResult() {Data=site,JsonRequestBehavior=JsonRequestBehavior.AllowGet };}function btn6() {$.ajax({url: "Web/getSiteById/",type:"get",data: { id:3 },traditional: true,async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data.Title);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}?
?
二、post請求
post請求的基礎類型的參數和get請求有點不一樣,我們知道get請求的參數是通過url來傳遞的,而post請求則是通過http的請求體中傳過來的,WebApi的post請求也需要從http的請求體里面去取參數。
如果按照通常的情況去傳參就有錯,比如:
解決方法之一是用[FromBody]在SaveString函數中修飾參數:public string SaveString([FromBody]string txt),然后再ajax中:data: {“”:"ff"},但是這個方法有一個缺點就是只能適用單一參數的情況,多參數就不行了
dynamic實現多參數傳遞,單一參數也可以
function ptn1() {$.ajax({type: 'post',url: "http://localhost:6972/api/values/SaveString",data: JSON.stringify({ NAME: "Jon", DES: "備注" }),traditional: true,contentType: 'application/json',async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}[HttpPost]public string SaveString(dynamic txt){return "保存:" + txt.NAME+"-"+txt.DES;}?
function ptn2() {$.ajax({type: 'post',url: "http://localhost:6972/api/values/SaveSite",data: JSON.stringify({ id: 3 }),traditional: true,contentType: 'application/json',async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data.Title);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}[HttpPost]public Site SaveSite(dynamic obj){SiteSource ss = new SiteSource();string s = obj.id;//int ID = int.Parse(obj.id); 這種方式有錯int ID =int.Parse(s);return ss.DateSource().Where(o => o.SiteId == ID).FirstOrDefault();}?
將實體作為參數傳遞。這里的實體更上面post方式的第一個例子是不同的,那個例子是傳遞多個參數的情況
function ptn3() {$.ajax({type: 'post',url: "http://localhost:6972/api/values/UpdateName",data: { SiteId: "1", Title: "test", Uri: "www.cnblogs.cc" },traditional: true,//contentType: 'application/json',async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}[HttpPost]public string UpdateName(Site si){SiteSource ss = new SiteSource();Site s= ss.DateSource().Where(o => o.SiteId == si.SiteId).FirstOrDefault();return s.Title + "123";}使用實體作為參數的時候,前端直接傳遞普通json,后臺直接使用對應的類型去接收即可,不用FromBody。但是這里需要注意的一點就是,這里不能指定contentType為appplication/json,否則,參數無法傳遞到后臺。
?post請求默認是將表單里面的數據的key/value形式發送到服務,而我們的服務器只需要有對應的key/value屬性值的對象就可以接收到。而如果使用application/json,則表示將前端的數據以序列化過的json傳遞到后端,后端要把它變成實體對象,還需要一個反序列化的過程。按照這個邏輯,那我們如果指定contentType為application/json,然后傳遞序列化過的對象應該也是可以的 ?
?
2、實體與基礎類型同時傳遞
function ptn4() {var postdata = { SiteId: "1", Title: "test", Uri: "www.cnblogs.cc" };$.ajax({type: 'post',url: "http://localhost:6972/api/values/SameName",data: JSON.stringify({ NAME: "test", o: postdata }), traditional: true,contentType: 'application/json',async: true,success: function (data, status) {if (status == "success") {alert(data); }else {$.ligerDialog.alert("", "操作失敗", "error");}}});}[HttpPost]public bool SameName(dynamic obj){string strName = Convert.ToString(obj.NAME);Site oCharging = Newtonsoft.Json.JsonConvert.DeserializeObject<Site>(Convert.ToString(obj.o));return strName==oCharging.Title;}3、基礎類型數組作為參數
function ptn5() {var arr = ["1", "2", "3", "4"];$.ajax({type: "post",url: "http://localhost:6972/api/values/SaveData1",contentType: 'application/json',data: JSON.stringify(arr),success: function (data, status) {if (status == "success") {alert(data);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});[HttpPost]public bool SaveData1(string[] ids){if (ids[0] == "1")return true;elsereturn false;}4、實體類型數組作為參數
?
function ptn6() {var arr = [{ SiteId: "1", Title : "test", Uri : "www.cnblogs.cc" },{ SiteId: "2",Title : "博客園首頁", Uri :"www.cnblogs.com" },{ SiteId: "3", Title: "博問", Uri: "q.cnblogs.com" }];$.ajax({type: "post",url: "http://localhost:6972/api/values/SaveData2",contentType: 'application/json',data: JSON.stringify(arr),success: function (data, status) {if (status == "success") {alert(data);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}[HttpPost]public bool SaveData2(List<Site> lstSite){if (lstSite[0].Title == "test")return true;elsereturn false;}5、post后臺調用
function ptn7() {$.ajax({url: "Web/PostReques/",type: "post",data: {},traditional: true,async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}mvc控制器中的相應函數
public JsonResult PostReques() {//請求路徑string url = "http://localhost:6972/api/values/UpdateName";//定義request并設置request的路徑WebRequest request = WebRequest.Create(url);request.Method = "post";//初始化request參數string postData = "{SiteId: \"2\",Title : \"博客園首頁\", Uri :\"www.cnblogs.com\" }";//設置參數的編碼格式,解決中文亂碼byte[] byteArray = Encoding.UTF8.GetBytes(postData);//設置request的MIME類型及內容長度request.ContentType = "application/json";request.ContentLength = byteArray.Length;//打開request字符流Stream dataStream = request.GetRequestStream();dataStream.Write(byteArray, 0, byteArray.Length);dataStream.Close();//定義response為前面的request響應WebResponse response = request.GetResponse();//獲取相應的狀態代碼 Console.WriteLine(((HttpWebResponse)response).StatusDescription);//定義response字符流dataStream = response.GetResponseStream();StreamReader reader = new StreamReader(dataStream);string responseFromServer = reader.ReadToEnd();//讀取所有return new JsonResult() { Data = responseFromServer};?
?三、put請求
WebApi里面put請求一般用于對象的更新。它和用法和post請求基本相同。同樣支持[FromBody],同樣可以使用dynamic。
function puttn() {$.ajax({type: 'put',url: "http://localhost:6972/api/values/PutData",data: JSON.stringify({ txt: "Jon"}),traditional: true,contentType: 'application/json',async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}[HttpPut]public string PutData(dynamic txt){return "123" + txt;}四、delete請求
delete請求肯定是用于刪除操作的。參數傳遞機制和post也是基本相同。下面簡單給出一個例子,其他情況參考post請求。
function deletetn() {$.ajax({type: 'delete',url: "http://localhost:6972/api/values/deleteData",data: JSON.stringify({ txt: "333333" }),traditional: true,contentType: 'application/json',async: true,success: function (data, status) {if (status == "success") {$("#div_test").html(data);}else {$.ligerDialog.alert("", "操作失敗", "error");}}});}[HttpDelete]public string deleteData(dynamic txt){return "----------" + txt;}?
轉載于:https://www.cnblogs.com/jin-/p/6605871.html
總結
- 上一篇: 【SoftwareTesting】Lab
- 下一篇: 接口的基本知识