WebAPI IE8、IE9 跨域问题

关于WebAPI跨域的问题,网上已经很多了,以下方案可以解决很多跨域问题,但是都不支持IE8、IE9浏览器,JSONP也只能支持Get请求

  1. 通过dll配置 Install-Package Microsoft.AspNet.WebApi.Cors
  2. 配置 Web.config

IE8,IE9跨域是通过XDomainRequest这个对象去实现,和XMLHttpRequest类似,可以参考下面文档

https://msdn.microsoft.com/zh-cn/library/dd573303(v=vs.85).aspx

使用jQuery.ajax的基础上,在jQuery下面再引用

https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest/blob/master/jQuery.XDomainRequest.js

这样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 }));
jQuery.XDomainRequest.js

加上消息处理就可以解决

 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;
            }
        }

posted @ 2016-10-14 16:55  xu_happy_you  阅读(1494)  评论(0编辑  收藏  举报