我有一个 SWF 对象的实现来修改 IE 的跨域请求的 XHR 对象。
一旦对象可用,我将像这样修改 XHR:
if ($.browser.msie) {
amplify.subscribe("request.before.ajax", function (resource, settings, ajaxSettings, xhr) {
if (resource.url.indexOf(requestConfig.apiUrl) != -1) {
xhr.setRequestHeader("Accept", "application/xml, text/xml");
var shr = new SWFHttpRequest();
ajaxSettings.xhr = function () {
return shr;
};
ajaxSettings.crossDomain = false;
ajaxSettings.error = function (e) {
// Returns the data object I expect:
alert(e.responseText);
}
}
});
};
我的 jQuery ajaxError 抛出的错误是: SyntaxError: Invalid character
- 该错误是由反斜杠引起的:
例如,当在我的 JSON 中:"Username" : "DOM\\PRO4"
它以某种方式进入"DOM\PRO4"
浏览器并给出语法错误。但是服务器正在转义,因为我可以看到从服务器发送的原始数据有 \ 但由于某种原因,我可以理解闪存可能会破坏这一点。
来自 IE 的响应正文是:
{
"ResponseCode": 200,
"ResponseDescription": "OK",
"ResponseEntity": [
{
"Id": "6d0d9471-f118-4984-9182-a20300a037b6",
"Name": "DYN",
"ConnectionTypeId": "20000000-0000-0000-0003-000000000003",
"ConnectionTypeName": null,
"Address": "http://54.229.51.444:7777/CRMServer",
"UserName": "DOM\\PRO4",
"Password": "",
"AddedById": "20000000-0000-0000-0004-000000000001",
"DateAdded": "07/22/2013 09:43:20",
"DateModified": "22/07/2013 15:00:01",
"ModifiedById": "",
"TypeName": "Dynamics"
}
]
}
您可以看到用户名已正确转义,但 ajax 设置错误警报显示 responseText 中的用户名只有 1 个反斜杠。
如果您还需要查看 SWF 对象,它是使用 haxe 开发的开源模块的修改版本:
import flash.external.ExternalInterface;
import flash.Lib;
import haxe.Http;
import flash.events.Event;
import flash.external.ExternalInterface;
import flash.display.Sprite;
class SWFHttpRequest {
public static var ver:String = '0.3';
public static var transports:Map<String,Transport> = new Map();
public static function abort( instance:Int ) {
transports.get( instance + '' ).abort();
}
public static function open( instance:Int, method:String, url:String ) {
transports.set( instance + '', new Transport( instance, method, url ) );
}
public static function send( instance:Int, data:String ) {
transports.get( instance + '' ).send( data );
}
public static function setRequestHeader( instance:Int, header:String, value:String ) {
transports.get( instance + '' ).setRequestHeader( header, value );
}
public static function version() {
return ver;
}
private static function onLoaded(event:Event):Void
{
flash.external.ExternalInterface.call("swfHttpLoaded");
}
public static function main() {
flash.system.Security.allowDomain("*");
ExternalInterface.addCallback("abort",abort);
ExternalInterface.addCallback("open",open);
ExternalInterface.addCallback("send",send);
ExternalInterface.addCallback("setRequestHeader",setRequestHeader);
ExternalInterface.addCallback("SWFHttpRequestVersion",version);
ExternalInterface.call( [ "(function(){",
"if (window.SWFHttpRequest) return;",
"var Class = function(properties){",
"var klass = function(){ return this.abort.apply(this); };",
"klass.prototype = properties;",
"klass.constructor = arguments.callee;",
"return klass;",
"};",
"window.SWFHttpRequest = new Class({",
"abort: function(){",
"if (typeof this.instance != 'undefined') {",
"window.SWFHttpRequest.instances[this.instance] = null;",
"window.SWFHttpRequest.engine.abort( this.instance );",
"}",
"this.readyState = 0;",
"this.responseText = '';",
"this.responseXML = null;",
"this.status = 0;",
"this.statusText = '';",
"this.instance = window.SWFHttpRequest.instances.length;",
"window.SWFHttpRequest.instances.push( this );",
"},",
"getAllResponseHeaders: function(){ return null; },",
"getResponseHeader: function(){ return null; },",
"onreadystatechange: null,",
"open: function(method, url, async, user, password){",
"this.status = 0;",
"this.readyState = 1;",
"this.statusText = this.responseText = '';",
"this.responseXML = null;",
"window.SWFHttpRequest.engine.open( this.instance, method, url );",
"},",
"send: function(data){",
// TODO: Once haxe.Http supports setPostData() for flash9 targets, this function
// should be updated to allow for a Document as the data. When that's the case,
// it should be serialized as XML prior to sending over to the Flash executor.
"window.SWFHttpRequest.engine.send( this.instance, data );",
"},",
"setRequestHeader: function(header, value){",
"if (this.readyState != 1 || !header || !value) return;",
"window.SWFHttpRequest.engine.setRequestHeader( this.instance, header, value );",
"}",
"});",
"window.SWFHttpRequest.instances = [];",
"window.SWFHttpRequest.version = '" + ver + "';",
"var f = function(tag){",
"var elems = document.getElementsByTagName(tag);",
"for (var i=0; i<elems.length; i++) if (elems[i].SWFHttpRequestVersion) return elems[i];",
"};",
"window.SWFHttpRequest.engine = f('embed') || f('object');",
"})" ].join('') );
var params = Lib.current.loaderInfo.parameters;
if (Reflect.hasField(params,'onload')) ExternalInterface.call( Reflect.field(params,'onload') );
Lib.current.loaderInfo.addEventListener(Event.COMPLETE, onLoaded);
}
}
class Transport {
var active:Bool;
var instance:Int;
var method:String;
var url:String;
var http:Http;
public function new( instance:Int, method:String, url:String ) {
this.active = true;
this.instance = instance;
this.method = method.toUpperCase();
this.url = url;
this.http = new Http( this.url );
this.http.onData = this.onData;
this.http.onError = this.onError;
this.http.onStatus = this.onStatus;
}
public function send( ?data:String ) {
if ( data==null ) return this.http.request( this.method=='POST' );
// NOTE: Once haxe.Http supports the setPostData() method for flash9 targets,
// all the following should be replaced by: this.http.setPostData( data );
// var re = ~/^(.*?)=(.*)$/;
// var pairs:Array<String> = data.split('&');
// var ud = function(s){
// try { return StringTools.urlDecode(s); }
// catch ( e:Dynamic ) { }
// return s;
// };
// for( i in 0...pairs.length ) {
// if (re.match(pairs[i])) this.http.setParameter( ud(re.matched(1)), ud(re.matched(2)) );
// else this.http.setParameter( ud(pairs[i]), '' );
// }
this.http.setPostData( data );
return this.http.request( this.method=='POST' );
}
public function setRequestHeader( header:String, value:String ) {
this.http.setHeader( header, value );
}
public function onData( data:String ) {
if (!this.active) return;
ExternalInterface.call( [ "(function(instance, data){",
"var shr = window.SWFHttpRequest.instances[instance];",
"if (!shr) return;",
"shr.status = 200;",
"shr.statusText = 'OK';",
"shr.readyState = 4;",
"shr.responseText = data;",
"try {",
"if (window.DOMParser) {",
"var dp = new DOMParser();",
"shr.responseXML = dp.parseFromString( data, 'text/xml' );",
"} else {",
"shr.responseXML = new ActiveXObject('Microsoft.XMLDOM');",
"shr.responseXML.async = 'false';",
"shr.responseXML.loadXML(data);",
"}",
"} catch(error) { shr.responseXML = null; }",
"if (shr.onreadystatechange && typeof shr.onreadystatechange=='function') shr.onreadystatechange();",
"})" ].join(''), this.instance, data);
}
public function onError( msg:String ) {
if (!this.active) return;
ExternalInterface.call( [ "(function(instance){",
"var shr = window.SWFHttpRequest.instances[instance];",
"if (!shr) return;",
"shr.status = 404;",
"shr.statusText = 'Not Found';",
"shr.readyState = 4;",
"shr.responseText = null;",
"shr.responseXML = null;",
"if (shr.onreadystatechange && typeof shr.onreadystatechange=='function') shr.onreadystatechange();",
"})" ].join(''), this.instance );
}
public function onStatus( status:Int ) {
if (!this.active || status==200) return;
ExternalInterface.call( [ "(function(instance, status){",
"var shr = window.SWFHttpRequest.instances[instance];",
"if (!shr) return;",
"shr.status = status;",
"if (shr.onreadystatechange && typeof shr.onreadystatechange=='function') shr.onreadystatechange();",
"})" ].join(''), this.instance, status );
}
public function abort() {
this.active = false;
}
}
//