最近项目中要用到mvc4的webapi,其实就是类似webservers wcf的东东( 虽然我都没用过,但是功能和用处还是知道的)作为接口使用,webapi有个好处就是可以把实现IEnumberable接口的数据能根据请求的返回数据类型(xml或者json)自动序列化成这样结构的数据,默认情况下chrome返回的是xml,IE返回的是Json。
既然是Api肯定是要让其他程序去调用的,webapi只能通过http协议去调用,在我们的项目中是静态页面中通过Ajax去调用的。那么问题就出来了 既然是在静态页面中,肯定是用在其他项目中或者在本地了,这样的话去调用webapi就是跨域访问了,要跨域当然我们会想到jQuery的几个跨域访问的方法,例如:$.get()
$.getJSON() $.getScript() $.ajax() 其实这几个在jQuery内部调用的都是$.ajax()。实验了一下才知道用这些方法实现跨域访问必须要在url后面加一个callback=?(?也不能省,jQuery会给我们添上该是什么的,每一次都不一样,为了回调的时候知道是哪个请求发出的。当然在$.ajax()方法中也可指定jsoncallback参数,发出请求后就是?的值)才行,并且返回的时候也要加在返回值得前面。例如webapi的url是www.asss.com/api/values
那么就是www.asss.com/api/values?callback=? 后台返回json格式之前要加callback的值 如:jsoncallback+"("+json+")"" jsoncallback是callback传过去的值 json是json内容 只有这样才能跨域请求成功,否则将会有jQuery报的异常 内容为.....is not called,就是返回来的时候传过去的callback方法没有被执行。造成返回的json字符串也取不到。 虽然说前后都加callback可以跨域成功,但是webapi貌似做个很多处理,要是返回json字符串在chrome浏览器中看到的返回值竟然被加了”“在最外边,在一般的处理程序返回json就不会加引号,这样的话要在前面加上callback也不会被认出来,想到会不会有在response的时候可以处理的可继承的方法,但是没找到
好像有request时候的。
还好msdn上有个大牛给了个解决方案,链接为http://code.msdn.microsoft.com/windowsdesktop/Implementing-CORS-support-a677ab5d还有源码下载挺好,大致意思是在跨域的ajax请求中,在request的头部加个Origin什么之类的。具体做法是建个继承
DelegatingHandler类的子类,重写SendAsync方法
该类内容如下:
c#代码
02
|
using System.Collections.Generic;
|
06
|
using System.Threading;
|
07
|
using System.Threading.Tasks;
|
11
|
namespace Mvc4WebApiTest
|
13
|
public class MessageHandler
: System.Net.Http.DelegatingHandler
|
16
|
const string Origin
= "Origin" ;
|
17
|
const string AccessControlRequestMethod
= "Access-Control-Request-Method" ;
|
18
|
const string AccessControlRequestHeaders
= "Access-Control-Request-Headers" ;
|
19
|
const string AccessControlAllowOrigin
= "Access-Control-Allow-Origin" ;
|
20
|
const string AccessControlAllowMethods
= "Access-Control-Allow-Methods" ;
|
21
|
const string AccessControlAllowHeaders
= "Access-Control-Allow-Headers" ;
|
24
|
protected override Task<httpresponsemessage>
SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
26
|
bool isCorsRequest
= request.Headers.Contains(Origin);
|
27
|
bool isPreflightRequest
= request.Method == HttpMethod.Options;
|
30
|
if (isPreflightRequest)
|
32
|
return Task.Factory.StartNew<httpresponsemessage>(()
=>
|
34
|
HttpResponseMessage
response = new HttpResponseMessage(HttpStatusCode.OK);
|
35
|
response.Headers.Add(AccessControlAllowOrigin,
request.Headers.GetValues(Origin).First());
|
38
|
string accessControlRequestMethod
= request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault();
|
39
|
if (accessControlRequestMethod
!= null )
|
41
|
response.Headers.Add(AccessControlAllowMethods,
accessControlRequestMethod);
|
45
|
string requestedHeaders
= string .Join( ",
" ,
request.Headers.GetValues(AccessControlRequestHeaders));
|
46
|
if (! string .IsNullOrEmpty(requestedHeaders))
|
48
|
response.Headers.Add(AccessControlAllowHeaders,
requestedHeaders);
|
53
|
},
cancellationToken);
|
57
|
return base .SendAsync(request,
cancellationToken).ContinueWith<httpresponsemessage>(t =>
|
59
|
HttpResponseMessage
resp = t.Result;
|
60
|
resp.Headers.Add(AccessControlAllowOrigin,
request.Headers.GetValues(Origin).First());
|
67
|
return base .SendAsync(request,
cancellationToken);
|
71
|
}</httpresponsemessage></httpresponsemessage></httpresponsemessage>
|
然后再GlobalApplication_Start的时候注册一下就行了
GlobalConfiguration.Configuration.MessageHandlers.Add(newMessageHandler());
测试成功! 前台调用就是普通的ajax请求地址就行了。
但是页面测试时发现IE浏览器8,9在Jquery ajax与后台通信管道中Handler类的前提下,跨域问题还是存在,Jquery抛出异常“No Transport” js前加上“jQuery.support.cors = true;”后浏览器报错“Error:拒绝访问”,查找资料,有两种办法
1.设置IE的安全性,当然不可取(这样的话每个用户都要设置)。
2.IE8 9可通过XDomainRequest对象(http://msdn.microsoft.com/zh-cn/library/dd573303(v=vs.85).aspx)发出跨域请求
但是只能发生get请求。 综合考虑:先继续寻找XDomainRequest发生post等的方法,否则只能在IE8 9种都设置发送get。
javascript代码
01
|
if ($.browser.msie
&& parseInt($.browser.version, 10) >= 6 && window.XDomainRequest) {
|
02
|
var xdr
= new XDomainRequest();
|
03
|
alert(xdr.responseText);
|
04
|
var data
= $.parseJSON(xdr.responseText);
|
05
|
if (data
== null || typeof (data)
== 'undefined' )
{
|
06
|
data
= $.parseJSON(data.firstChild.textContent);
|
10
|
xdr.onsuccess
= function ()
{ };
|
11
|
xdr.onerror
= function (e)
{
|
12
|
alert(xdr.responseText);
alert(e);
|
15
|
xdr.onload
= function (e)
{
|
17
|
xdr.open( "post" ,
url);
|
18
|
xdr.send( "dd:dd&ss:ss" );
|
21
|
var xhr
= jQuery.ajax({
|
26
|
data:{SystemName:
myModel.systemname(), SystemIp: myModel.systemip(), ContactPerson: myModel.contactperson() },
|
27
|
success: function (msg)
{ alert(msg); var jsonmsg
= eval( "(" +
msg + ")" );
alert(jsonmsg.state); },
|
28
|
complete: function ()
{ },
|
29
|
error: function (a,
b, c) { alert( "shibai" +
a + "-" +
b + "-" +
c); alert(c); }
|
测试得知XDomainRequest只能发送get和post的请求,并且由于post请求报文头中一定要有“Content-Type:application/x-www-form-urlencoded”
(非提交文件时,有file标签时好像是application/..form-file)因为XDomainRequest的Content-Type是只读的‘text/plain’所以post不能提交数据,否则就会出错或者后台取不到数据。要想用就只能用get了。 而我最后 放弃web api 改用普通mvc 前台jsonp请求。(jsonp介绍请移步http://www.dnetzj.com/Content/198.html)
jquery的ajax也很简单:
javascript代码
4
|
jsonpCallback: 'callback' ,
|
6
|
success: function (msg){}
|
以上写的比较乱还是总结一下吧, 如果要在页面跨域访问还是用jsonp方便一点,但因jsonp是以增加script文件,执行完再删除的形式所以jsonp只能发送get请求,所以如果要提交文件就用uploadify插件(flash上传)(参见:回头再说:Uploadify跨域上传原理),要提交的内容长度比较多时就用ajaxcdr.js(flash请求)(参见:jsonp请求url长度过长的替代(ajaxcdr的使用))
分享到:
相关推荐
WebApi跨域访问 ASP.NET MVC4客户端 html客户端;
简单例子这是关于Jquery调用WebAPI跨域的例子。
Web API跨域的方法有很多,这里给出最简单而又最实用的一种。希望可以帮到您。Web API跨域的方法有很多,这里给出最简单而又最实用的一种。希望可以帮到您。
ASP.NET MVC Web Api 跨域访问
今天就来讨论一下其中之一的问题,WebAPI与前端Ajax 进行跨域数据交互时,由于都在不同的二级域名下(一级域名相同),导致Cookies数据无法获取。 最开始通过头部(Header)将Cookies传输到其WebAPI,也能解决问题。...
摘要: 大概思路,创建WebAPI,CrossMainController并编写,Nuget安装microsoft.aspnet.webapi.cors., 跨域设置路由,WebAPI提供广泛的对外开放,可以起到整合性的作用,例如:跟Oracle ERP、SAP的SCM、MM、PP以及SD领域...
同源策略:出于安全考虑,浏览器会限制脚本中发起的跨站请求,浏览器要求JavaScript或Cookie只能访问同域下的内容。...因为我们的WebApi和MVC是两个不同的项目,所以运行起来之后就存在上面说的跨域的问题。
但是在使用API的时候总会遇到跨域请求的问题,特别各种APP万花齐放的今天,API的跨域请求是不能避免的。 在默认情况下,为了防止CSRF跨站的伪造攻击(或者是 javascript的同源策略(Same-Origin Policy)),一个网页...
webapi跨域小demon,适合刚学者,没什么技术难点,自己测试过,跨域成功 同源策略:出于安全考虑,浏览器会限制脚本中发起的跨...因为我们的WebApi和MVC是两个不同的项目,所以运行起来之后就存在上面说的跨域的问题。
解决ajax跨域问题
webapi跨域处理类
Ajax跨域问题及其解决方案.docx
WebAPI:client客户端post提交签名数据/apiServer服务端返回json数据交互 客户端: Web/ApiClient/queryToken.aspx API服务端:Web/Api/ApiServe/queryToken.aspx 客户端(Web/ApiClient/queryToken.aspx )以post方式...
NULL 博文链接:https://chun521521.iteye.com/blog/1935516
WebApi跨域访问;
本案例演示了MVC如何设置跨域。
在做Web开发中,常常会遇到跨域的问题,到目前为止,已经有非常多的跨域解决方案...下面这篇文章主要给大家介绍了关于ASP.net WebAPI跨域调用问题的解决方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。
Jquery跨域访问Web服务的demo源码