WebAPI IE8、IE9 跨域问题
关于WebAPI跨域的问题,网上已经很多了,以下方案可以解决很多跨域问题,但是都不支持IE8、IE9浏览器,JSONP也只能支持Get请求
- 通过dll配置 Install-Package Microsoft.AspNet.WebApi.Cors
- 配置 Web.config
IE8,IE9跨域是通过XDomainRequest这个对象去实现,和XMLHttpRequest类似,可以参考下面文档
https://msdn.microsoft.com/zh-cn/library/dd573303(v=vs.85).aspx
使用jQuery.ajax的基础上,在jQuery下面再引用
这样IE8、IE9跨域成功了
public Response<string> Post() { Response<string> rs = new Response<string> { head = new ResponseHeader { errcode = 0, errmessage = "post" }, data = "hello" }; return rs; }
这样IE8、IE9跨域失败了
public Response<string> Post(Request<Message> request) { Response<string> rs = new Response<string> { head = new ResponseHeader { errcode = 0, errmessage = "post" }, data = request.data.content }; return rs; }
后来通过排查,有对象形参的WebAPI就会遇到反序列化问题,(IE8,IE9)转换为request对象的時候报错
试了很多次,前端帶不过來Content-Type,就想到了用參数传递到后端,也修改了jQuery.XDOmainRequest.js这个文件
1 /*! 2 * jQuery-ajaxTransport-XDomainRequest - v1.0.4 - 2015-03-05 3 * https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest 4 * Copyright (c) 2015 Jason Moon (@JSONMOON) 5 * Licensed MIT (/blob/master/LICENSE.txt) 6 */ 7 (function (factory) { 8 if (typeof define === 'function' && define.amd) { 9 // AMD. Register as anonymous module. 10 define(['jquery'], factory); 11 } else if (typeof exports === 'object') { 12 // CommonJS 13 module.exports = factory(require('jquery')); 14 } else { 15 // Browser globals. 16 factory(jQuery); 17 } 18 }(function ($) { 19 20 // Only continue if we're on IE8/IE9 with jQuery 1.5+ (contains the ajaxTransport function) 21 if ($.support.cors || !$.ajaxTransport || !window.XDomainRequest) { 22 return $; 23 } 24 25 var httpRegEx = /^(https?:)?\/\//i; 26 var getOrPostRegEx = /^get|post$/i; 27 var sameSchemeRegEx = new RegExp('^(\/\/|' + location.protocol + ')', 'i'); 28 29 // ajaxTransport exists in jQuery 1.5+ 30 $.ajaxTransport('* text html xml json', function (options, userOptions, jqXHR) { 31 32 // Only continue if the request is: asynchronous, uses GET or POST method, has HTTP or HTTPS protocol, and has the same scheme as the calling page 33 if (!options.crossDomain || !options.async || !getOrPostRegEx.test(options.type) || !httpRegEx.test(options.url) || !sameSchemeRegEx.test(options.url)) { 34 return; 35 } 36 37 var xdr = null; 38 39 return { 40 send: function (headers, complete) { 41 var postData = ''; 42 var userType = (userOptions.dataType || '').toLowerCase(); 43 44 xdr = new XDomainRequest(); 45 if (/^\d+$/.test(userOptions.timeout)) { 46 xdr.timeout = userOptions.timeout; 47 } 48 49 xdr.ontimeout = function () { 50 complete(500, 'timeout'); 51 }; 52 53 xdr.onload = function () { 54 var allResponseHeaders = 'Content-Length: ' + xdr.responseText.length + '\r\nContent-Type: ' + xdr.contentType; 55 var status = { 56 code: 200, 57 message: 'success' 58 }; 59 var responses = { 60 text: xdr.responseText 61 }; 62 try { 63 if (userType === 'html' || /text\/html/i.test(xdr.contentType)) { 64 responses.html = xdr.responseText; 65 } else if (userType === 'json' || (userType !== 'text' && /\/json/i.test(xdr.contentType))) { 66 try { 67 responses.json = $.parseJSON(xdr.responseText); 68 } catch (e) { 69 status.code = 500; 70 status.message = 'parseerror'; 71 //throw 'Invalid JSON: ' + xdr.responseText; 72 } 73 } else if (userType === 'xml' || (userType !== 'text' && /\/xml/i.test(xdr.contentType))) { 74 var doc = new ActiveXObject('Microsoft.XMLDOM'); 75 doc.async = false; 76 try { 77 doc.loadXML(xdr.responseText); 78 } catch (e) { 79 doc = undefined; 80 } 81 if (!doc || !doc.documentElement || doc.getElementsByTagName('parsererror').length) { 82 status.code = 500; 83 status.message = 'parseerror'; 84 throw 'Invalid XML: ' + xdr.responseText; 85 } 86 responses.xml = doc; 87 } 88 } catch (parseMessage) { 89 throw parseMessage; 90 } finally { 91 complete(status.code, status.message, responses, allResponseHeaders); 92 } 93 }; 94 95 // set an empty handler for 'onprogress' so requests don't get aborted 96 xdr.onprogress = function () { }; 97 xdr.onerror = function () { 98 complete(500, 'error', { 99 text: xdr.responseText 100 }); 101 }; 102 103 if (userOptions.data) { 104 postData = ($.type(userOptions.data) === 'string') ? userOptions.data : $.param(userOptions.data); 105 } 106 if (options.contentType && options.contentType.length > 0) { 107 if (options.url.indexOf('?') > -1) { 108 options.url = options.url + '&_contentType=' + options.contentType; 109 } else { 110 options.url = options.url + '?_contentType=' + options.contentType; 111 } 112 } 113 xdr.open(options.type, options.url); 114 xdr.send(postData); 115 }, 116 abort: function () { 117 if (xdr) { 118 xdr.abort(); 119 } 120 } 121 }; 122 }); 123 124 return $; 125 126 }));
加上消息处理就可以解决
public class CrossDomainFixIEHandler : DelegatingHandler { protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { if (request.Method == HttpMethod.Options) { HttpResponseMessage response = request.CreateResponse<string>(HttpStatusCode.OK, null); TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>(); tcs.SetResult(response); return tcs.Task; } if (request.Content.Headers.ContentType == null || string.IsNullOrWhiteSpace(request.Content.Headers.ContentType.MediaType)) { string contentType = this.GetContentType(string.Concat(request.RequestUri.Query, "&")); if (string.IsNullOrWhiteSpace(contentType)) { contentType = "application/json"; } request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType); } return base.SendAsync(request, cancellationToken); } /// <summary> /// 獲取ContentType /// </summary> /// <param name="source"></param> /// <returns></returns> private string GetContentType(string source) { if (string.IsNullOrWhiteSpace(source)) { return string.Empty; } Regex regex = new Regex("[&?]_contentType=(?<contentType>(.*?))&", RegexOptions.IgnoreCase); Match match = regex.Match(source); if (match.Success) { return match.Groups["contentType"].Value; } else { return string.Empty; } }
完