解决AjaxPro.2在SSL下无法正常调用问题
问题:AjaxPro在HTTPS环境中浏览器不兼容
客户要做二级等保,必须全面使用HTTPS协议。老项目中ajax调用基本用的是AjaxPro,2.0版本,在HTTPS下世界之窗之类的浏览器访问没有问题,但Chrome,360等浏览器都无法正常调用。
根源:ajaxpro/core.ashx脚本Error
通过跟踪发现是core.ashx返回的js脚本中,对于statusText的判断有不同,之前statusText值为"OK",现在statusText值为"",于是脚本判断认为error。
解决方案:替代core.ashx请求返回内容
- 整个项目绝大多数地方都用到这个脚本,而且页面js有相关依赖,无法从前端override这个js中的方法;
- 考虑从后端处理core.ashx请求,返回修改过的js脚本;
- 修改AjaxPro.2.core.js:
doStateChange: function() {
this.onStateChanged(this.xmlHttp.readyState, this);
if(this.xmlHttp.readyState != 4 || !this.isRunning) {
return;
}
this.duration = new Date().getTime() - this.__start;
if(this.timeoutTimer != null) {
clearTimeout(this.timeoutTimer);
}
var res = this.getEmptyRes();
if(this.xmlHttp.status == 200 && (this.xmlHttp.statusText == "OK" || this.xmlHttp.statusText == "")) {
res = this.createResponse(res);
} else {
res = this.createResponse(res, true);
res.error = {Message:this.xmlHttp.statusText,Type:"ConnectFailure",Status:this.xmlHttp.status};
}
this.endRequest(res);
},
- 可以考虑从Application_BeginRequest方法拦截该请求,并通过重写请求地址实现。但这种方式耦合性太高,暂不采用;
- 通过嵌入httpHandler方式处理core.ashx请求:
<httpHandlers>
<add path="AjaxPro/core.ashx" verb="GET" type="AjaxProExtention.AjaxHandlerFactory, AjaxProExtention" />
<add path="AjaxPro/*.ashx" verb="POST,GET" type="AjaxPro.AjaxHandlerFactory, AjaxPro.2" />
<add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="true" />
</httpHandlers>
其中AjaxProExtention是自定义的扩展处理程序,只接收'ajaxpro/core.ashx'请求,返回修改后的core.js;
- 自定义AjaxProExtention程序:
public void ProcessRequest(HttpContext context)
{
//AjaxPro.2原有方法逻辑
string etag = context.Request.Headers["If-None-Match"];
string str2 = context.Request.Headers["If-Modified-Since"];
if (context.Cache["AjaxPro." + this.fileName] != null)
{
CacheInfo info = (CacheInfo) context.Cache["AjaxPro." + this.fileName];
if ((etag != null) && (etag == info.ETag))
{
context.Response.StatusCode = 0x130;
return;
}
if (str2 != null)
{
if (str2.IndexOf(";") > 0)
{
str2 = str2.Split(new char[] { ';' })[0];
}
try
{
if (DateTime.Compare(Convert.ToDateTime(str2.ToString()).ToUniversalTime(), info.LastModified.ToUniversalTime()) >= 0)
{
context.Response.StatusCode = 0x130;
return;
}
}
catch (FormatException)
{
if (context.Trace.IsEnabled)
{
context.Trace.Write("AjaxPro", "The header value for If-Modified-Since = " + str2 + " could not be converted to a System.DateTime.");
}
}
}
}
etag = MD5Helper.GetHash(Encoding.Default.GetBytes(this.fileName));
DateTime now = DateTime.Now;
DateTime date = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
context.Response.AddHeader("Content-Type", "application/x-javascript");
context.Response.ContentEncoding = Encoding.UTF8;
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetETag(etag);
context.Response.Cache.SetLastModified(date);
//处理请求返回js资源
if ((this.fileName != null) && (this.fileName.Length > 0))
{
string[] strArray = this.fileName.Split(new char[] { ',' });
Assembly executingAssembly = Assembly.GetExecutingAssembly();
for (int i = 0; i < strArray.Length; i++)
{
Stream manifestResourceStream = executingAssembly.GetManifestResourceStream("AjaxProExtention.AjaxPro.2." + strArray[i] + ".js");
if (manifestResourceStream != null)
{
StreamReader reader = new StreamReader(manifestResourceStream);
context.Response.Write("// " + strArray[i] + ".js\r\n");
context.Response.Write(reader.ReadToEnd());
context.Response.Write("\r\n");
reader.Close();
}
}
}
context.Cache.Add("AjaxPro." + this.fileName, new CacheInfo(etag, date), null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
}
- 把编译得到的AjaxProExtention.dll放到项目程序bin目录中。
- 完成并调试。