回头再说:jQuery跨域原理 一文提到浏览器的同源策略以及使用JsonP的方式实现跨域;在评论中金色海洋提出了一个问题:

 

我最近在用 uploadify + ashx 来做文件上传的功能。都测试成功了,但是发现我可以提交到其他的网站里面。

我是在本地测试了。两个网站,IP地址相同,使用端口来区分。

一个端口是8001,另一个是8002 。

两个网站都有上传文件的程序,我发现,如果我把8001端口的站点的

'script': '/_CommonPage/UploadHandler.ashx',

改成

'script': 'http://192.168.0.1:8002/_CommonPage/UploadHandler.ashx',

居然也能够成功上传文件,传到了8002对应的网站里面。

我不知道如果换成域名了,是否也是可以往不同的域名里上传文件?

如果是的话,是不是很危险?如何来验证呢? 

 

 我给出的错误解释

         看到金色海洋的问题之后,我下载下来Uploadify源码看了一下,然后非常草率的给出了一个解释,点击这里;对于这个错误的解释,园友mx1700提出了质疑;于是下班回家之后,我开始动手模拟金色海洋的环境,试图一探究竟; 

 

Uploadify工作机制

       我在VS2010里面新建了一个webApplication,在页面上使用Uploadify,页面代码如下:   

    



<script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
<script src="Scripts/jquery.uploadify.v2.1.0.js" type="text/javascript"></script>
<script src="Scripts/swfobject.js" type="text/javascript"></script>
<script type="text/javascript">
// <![CDATA[
var id = "55";
var theString = "asdf";
$(document).ready(
function () {
$(
'#fileInput').uploadify({
'uploader': 'uploadify.swf',
'script': 'http://www.b.com:84/Uploader.ashx',
'scriptData': { 'id': id, 'foo': theString },
'cancelImg': 'cancel.png',
'auto': true,
'multi': true,
'fileDesc': 'Image Files',
'fileExt': '*.jpg;*.png;*.gif;*.bmp;*.jpeg',
'queueSizeLimit': 90,
'sizeLimit': 4000000,
'buttonText': 'Choose Images',
'folder': '/uploads',
'onAllComplete': function (event, queueID, fileObj, response, data) {

}
});
});
// ]]></script>

<input id="fileInput" name="fileInput" type="file" />

 

        通过单步调试,我发现页面上会通过swfobject.js动态加载一个Flash,我们在页面上操作的实际上是Flash.  jQuery的作用是页面、Flash、目标服务器之间的黏合剂。它定义用户上传操作在不同时机的响应函数.而在这里 我所认为“发送数据上传文件”的函数,只不过是一个用来检查服务器上是不是已经存在同名文件的函数;由于这个检查有可能是跨域,所以 Uploadify间接使用了jQuery的JsonP跨域解决方案.

        通过排除,我们能有一个基本的判断:文件上传是在Flash里面完成的.那么Flash里面做了什么呢?还好有uploadify.fla文件,使用Flex Builder打开这个文件来看,果然如此,很多朋友没有Flex Builde,这里贴出完整代码;可以看到,

// Upload each file
function uploadFile(file:FileReference, index:int, ID:String, single:Boolean):

    实际的上传操作,而上传不同时机使用的很多函数都是定义在jquery.uploadify.v2.1.0.min.js文件里面.

uploadify.fla
1 /*
2 Uploadify v2.1.0
3 Release Date: August 24, 2009
4
5 Copyright (c) 2009 Ronnie Garcia, Travis Nickels
6
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 THE SOFTWARE.
24  */
25
26 import flash.external.ExternalInterface;
27 import flash.net.*;
28 import flash.events.*;
29 import flash.display.*;
30 import com.adobe.serialization.json.JSON;
31
32  // Align the stage to the top left and don't scale it
33  stage.align = StageAlign.TOP_LEFT;
34 stage.scaleMode = StageScaleMode.NO_SCALE;
35
36  // Create all the variables
37  var param:Object = LoaderInfo(this.root.loaderInfo).parameters;
38  var fileRefSingle:FileReference = new FileReference();
39  var fileRefMulti:FileReferenceList = new FileReferenceList();
40  var fileRefListener:Object = new Object();
41  var fileQueue:Array = new Array();
42  var fileItem:Object = new Object();
43  var activeUploads:Object = new Object();
44  var errorArray:Array = new Array();
45  var counter:Number = 0;
46  var filesSelected:Number = 0;
47  var filesReplaced:Number = 0;
48  var filesUploaded:Number = 0;
49  var filesChecked:Number = 0;
50  var errors:Number = 0;
51  var kbs:Number = 0;
52 var allBytesLoaded:Number = 0;
53 var allBytesTotal:Number = 0;
54 var allKbsAvg:Number = 0;
55 var allowedTypes:Array;
56 var scriptURL:URLRequest;
57 var variables:URLVariables;
58 var queueReversed:Boolean = false;
59
60 // For debugging, alert any value to javascript
61 function debug(someValue) {
62 ExternalInterface.call('alert("' + someValue + '")');
63 }
64
65 // Trigger a javascript event
66 function $trigger(eventName:String, ... args):void {
67 // Add parenthesis
68 function p(s:String):String {
69 return ('('+s+')');
70 }
71 // Add quotes
72 function q(s:String):String {
73 return ('"'+s+'"');
74 }
75 var list:Array = [q(eventName)]; //Add the event to the array
76 if (args.length > 0) list.push(JSON.encode(args)); // Add arguments to the array as a JSON object
77 ExternalInterface.call(['jQuery'+p(q('#'+param.uploadifyID)), p(list.join(','))].join('.trigger')); // Trigger the event
78 }
79
80 // Random string generator for queue IDs
81 function generateID(len:Number):String {
82 var chars:Array = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
83 var ID:String = '';
84 var index:Number;
85 for (var n:int = 0; n < len; n++) {
86 ID += chars[Math.floor(Math.random() * 25)];
87 }
88 return ID;
89 }
90
91 // Load the button image
92 function setButtonImg():void {
93 if (param.buttonImg) {
94 var btnLoader:Loader = new Loader();
95 var btnImage:URLRequest = new URLRequest(param.buttonImg);
96 browseBtn.addChild(btnLoader);
97 btnLoader.load(btnImage);
98 }
99 if (!param.hideButton && !param.buttonImg) {
100 browseBtn.empty.alpha = 1;
101 }
102 }
103 setButtonImg();
104
105 // Hide or show the button
106 function hideButton(hideValue:Boolean):void {
107 if (hideValue) {
108 browseBtn.empty.alpha = 0;
109 } else {
110 browseBtn.empty.alpha = 1;
111 }
112 }
113
114 // Set the text on the button
115 function setButtonText():void {
116 if (param.buttonText) {
117 browseBtn.empty.buttonText.text = unescape(param.buttonText);
118 }
119 }
120 setButtonText();
121
122 // This is important for clicking the button correctly
123 browseBtn.buttonMode = true;
124 browseBtn.useHandCursor = true;
125 browseBtn.mouseChildren = false;
126
127 // Set the size of the button
128 function setButtonSize():void {
129 if (param.hideButton) {
130 browseBtn.width = param.width;
131 browseBtn.height = param.height;
132 }
133 // Set the size of the button on the page
134 ExternalInterface.call('jQuery("#' + param.uploadifyID + '").attr("width",' + param.width + ')');
135 ExternalInterface.call('jQuery("#' + param.uploadifyID + '").attr("height",' + param.height + ')');
136 }
137 setButtonSize();
138
139 // Setup the rollover animation
140 if (param.rollover) {
141 browseBtn.addEventListener(MouseEvent.ROLL_OVER, function (event:MouseEvent):void {
142 event.currentTarget.y = -param.height;
143 });
144 browseBtn.addEventListener(MouseEvent.ROLL_OUT, function (event:MouseEvent):void {
145 event.currentTarget.y = 0;
146 });
147 browseBtn.addEventListener(MouseEvent.MOUSE_DOWN, function (event:MouseEvent):void {
148 event.currentTarget.y = -(param.height * 2);
149 });
150 }
151
152 // create the scriptData variable if it doesn't exist
153 if (!param.scriptData) {
154 param.scriptData = '';
155 }
156
157 // Limit the file types
158 function setAllowedTypes():void {
159 allowedTypes = [];
160 if (param.fileDesc && param.fileExt) {
161 var fileDescs:Array = param.fileDesc.split('|');
162 var fileExts:Array = param.fileExt.split('|');
163 for (var n = 0; n < fileDescs.length; n++) {
164 allowedTypes.push(new FileFilter(fileDescs[n], fileExts[n]));
165 }
166 }
167 }
168 setAllowedTypes();
169
170 // Set or get the variables
171 function uploadify_updateSettings(settingName:String, settingValue) {
172 if(settingValue == null) {
173 if (settingName == 'queueSize') {
174 return fileQueue.length;
175 }
176 return param[settingName];
177 } else {
178 param[settingName] = settingValue;
179 if(settingName == 'buttonImg') setButtonImg();
180 if(settingName == 'buttonText') setButtonText();
181 if(settingName == 'fileDesc' || settingName == 'fileExt') setAllowedTypes();
182 if(settingName == 'width' || settingName == 'height') setButtonSize();
183 if(settingName == 'hideButton') hideButton(settingValue);
184 return true;
185 }
186 }
187
188 // Browse for Files
189 browseBtn.addEventListener(MouseEvent.CLICK, function():void {
190 if (objSize(activeUploads) == 0) { // Don't browse if it's uploading
191 if (!allowedTypes) {
192 (!param.multi) ? fileRefSingle.browse() : fileRefMulti.browse();
193 } else {
194 (!param.multi) ? fileRefSingle.browse(allowedTypes) : fileRefMulti.browse(allowedTypes);
195 }
196 }
197 });
198
199 // Get the size of an object
200 function objSize(obj:Object):Number {
201 var i:int = 0;
202 for (var item in obj) {
203 i++;
204 }
205 return i;
206 }
207
208 // Get actual folder path
209 function getFolderPath():String {
210 var folder:String = param.folder;
211 if (param.folder.substr(0,1) != '/' && param.folder.substr(0,4) != 'http') {
212 folder = param.pagepath + param.folder;
213 var folderParts:Array = folder.split('/');
214 for (var i = 0; i < folderParts.length; i++) {
215 if (folderParts[i] == '..') {
216 folderParts.splice(i - 1, 2);
217 }
218 }
219 folder = folderParts.join('/');
220 }
221 return folder;
222 }
223
224 // Get the array index of the item in the fileQueue
225 function getIndex(ID:String):Number {
226 var index:int;
227 for (var n:Number = 0; n < fileQueue.length; n++) {
228 if (fileQueue[n].ID == ID) {
229 index = n;
230 }
231 }
232 return index;
233 }
234
235 // Check if a file with the same name is already in the queue
236 function inQueue(fileName:String):Object {
237 var obj:Object = new Object();
238 obj.testResult = false;
239 if (fileQueue.length > 0) {
240 for (var n = 0; n < fileQueue.length; n++) {
241 if (fileQueue[n].file.name == fileName) {
242 obj.size = fileQueue[n].file.size;
243 obj.ID = fileQueue[n].ID;
244 obj.arrIndex = n;
245 obj.testResult = true;
246 }
247 }
248 }
249 return obj;
250 }
251
252 // When selecting a file
253 function fileSelectSingleHandler(event:Event):void {
254 // Check if the filename already exists in the queue
255 fileItem = new Object();
256 fileItem.file = FileReference(event.target);
257 uploadify_clearFileUploadQueue(true);
258 var ID:String = generateID(6);
259 fileItem.ID = ID;
260 fileQueue.push(fileItem);
261 filesSelected = 1;
262 allBytesTotal = fileItem.file.size;
263 $trigger('uploadifySelect',ID,fileItem.file);
264 $trigger('uploadifySelectOnce',{
265 'fileCount' : fileQueue.length,
266 'filesSelected' : filesSelected,
267 'filesReplaced' : filesReplaced,
268 'allBytesTotal' : allBytesTotal
269 });
270 filesSelected = 0;
271 filesReplaced = 0;
272 if (param.auto) {
273 if (param.checkScript) {
274 uploadify_uploadFiles(null, false);
275 } else {
276 uploadify_uploadFiles(null, true);
277 }
278 }
279 }
280
281 function fileSelectMultiHandler(event:Event):void {
282 var ID:String = '';
283 for (var n:Number = 0; n < fileRefMulti.fileList.length; n++) {
284 fileItem = new Object();
285 fileItem.file = fileRefMulti.fileList[n];
286 // Check if the filename already exists in the queue
287 var queueTest:Object = inQueue(fileRefMulti.fileList[n].name);
288 if (queueTest.testResult) {
289 allBytesTotal -= queueTest.size;
290 allBytesTotal += fileItem.file.size;
291 fileItem.ID = fileQueue[queueTest.arrIndex].ID;
292 fileQueue[queueTest.arrIndex] = fileItem;
293 filesReplaced++;
294 } else {
295 if (fileQueue.length < param.queueSizeLimit) {
296 ID = generateID(6);
297 fileItem.ID = ID;
298 fileQueue.push(fileItem);
299 filesSelected++;
300 allBytesTotal += fileItem.file.size;
301 $trigger('uploadifySelect',ID,fileItem.file);
302 } else {
303 $trigger('uploadifyQueueFull',param.queueSizeLimit);
304 break;
305 }
306 }
307 }
308 $trigger('uploadifySelectOnce',{
309 'fileCount' : fileQueue.length,
310 'filesSelected' : filesSelected,
311 'filesReplaced' : filesReplaced,
312 'allBytesTotal' : allBytesTotal
313 });
314 filesSelected = 0;
315 filesReplaced = 0;
316 if (param.auto) {
317 if (param.checkScript) {
318 uploadify_uploadFiles(null, false);
319 } else {
320 uploadify_uploadFiles(null, true);
321 }
322 }
323 }
324 fileRefSingle.addEventListener(Event.SELECT, fileSelectSingleHandler);
325 fileRefMulti.addEventListener(Event.SELECT, fileSelectMultiHandler);
326
327 // This function should run during upload so flash doesn't timeout
328 function uploadCounter(event:Event):void {
329 counter++;
330 }
331
332 // Start the upload
333 function uploadify_uploadFiles(ID:String, checkComplete:Boolean):void {
334 if (!queueReversed) {
335 fileQueue.reverse();
336 queueReversed = true;
337 }
338 if (param.script.substr(0,1) != '/' && param.script.substr(0,4) != 'http') param.script = param.pagepath + param.script;
339 scriptURL = new URLRequest(param.script);
340 variables = new URLVariables();
341 (param.method.toUpperCase() == "GET") ? scriptURL.method = URLRequestMethod.GET : scriptURL.method = URLRequestMethod.POST;
342 if (param.scriptData != '') variables.decode(unescape(param.scriptData));
343 if (param.fileExt) variables.fileext = unescape(param.fileExt);
344 variables.folder = unescape(getFolderPath());
345 scriptURL.data = variables;
346 if (param.checkScript && !checkComplete) {
347 var fileQueueObj:Object = new Object();
348 if (ID) {
349 var index:int = getIndex(ID);
350 if (fileQueue[index].file) {
351 fileQueueObj[fileQueue[index].ID] = fileQueue[index].file.name;
352 }
353 $trigger('uploadifyCheckExist',param.checkScript,fileQueueObj,param.folder,true);
354 } else {
355 for (var n:Number = fileQueue.length - 1; n > -1; n--) {
356 if (fileQueue[n]) {
357 fileQueueObj[fileQueue[n].ID] = fileQueue[n].file.name;
358 }
359 }
360 $trigger('uploadifyCheckExist',param.checkScript,fileQueueObj,param.folder,false);
361 }
362 } else {
363 if (ID && fileQueue[getIndex(ID)].file) {
364 uploadFile(fileQueue[getIndex(ID)].file, getIndex(ID), ID, true);
365 } else {
366 for (n = fileQueue.length - 1; n > -1; n--) {
367 if (objSize(activeUploads) < parseInt(param.simUploadLimit)) {
368 if (!activeUploads[fileQueue[n].ID] && fileQueue[n].file) {
369 uploadFile(fileQueue[n].file, n, fileQueue[n].ID, false);
370 }
371 } else {
372 break;
373 }
374 }
375 }
376 }
377 }
378
379 function queueIsNotEmpty(item:*, index:int, array:Array):Boolean {
380 return (item.file != '');
381 }
382
383 // Upload each file
384 function uploadFile(file:FileReference, index:int, ID:String, single:Boolean):void {
385 var startTimer:Number = 0;
386 var lastBytesLoaded:Number = 0;
387 var kbsAvg:Number = 0;
388
389 function fileOpenHandler(event:Event) {
390 startTimer = getTimer();
391 $trigger('uploadifyOpen',ID,event.currentTarget);
392 }
393
394 function fileProgressHandler(event:ProgressEvent):void {
395 var percentage:Number = Math.round((event.bytesLoaded / event.bytesTotal) * 100);
396 if ((getTimer()-startTimer) >= 150) {
397 kbs = ((event.bytesLoaded - lastBytesLoaded)/1024)/((getTimer()-startTimer)/1000);
398 kbs = int(kbs*10)/10;
399 startTimer = getTimer();
400 if (kbsAvg > 0) {
401 kbsAvg = (kbsAvg + kbs)/2;
402 } else {
403 kbsAvg = kbs;
404 }
405 allKbsAvg = (allKbsAvg + kbsAvg)/2;
406 }
407 allBytesLoaded += (event.bytesLoaded - lastBytesLoaded);
408 lastBytesLoaded = event.bytesLoaded;
409 $trigger('uploadifyProgress',ID,event.currentTarget,{
410 'percentage' : percentage,
411 'bytesLoaded' : event.bytesLoaded,
412 'allBytesLoaded' : allBytesLoaded,
413 'speed' : kbs
414 });
415 }
416
417 function fileCompleteHandler(event:DataEvent):void {
418 if (kbsAvg == 0) {
419 kbs = (file.size/1024)/((getTimer()-startTimer)/1000);
420 kbsAvg = kbs;
421 allKbsAvg = (allKbsAvg + kbsAvg)/2;
422 }
423
424 allBytesLoaded -= lastBytesLoaded;
425 allBytesLoaded += event.currentTarget.size;
426
427 $trigger('uploadifyProgress',ID,event.currentTarget,{
428 'percentage' : 100,
429 'bytesLoaded' : event.currentTarget.size,
430 'allBytesLoaded' : allBytesLoaded,
431 'speed' : kbs
432 });
433 $trigger('uploadifyComplete',ID,{
434 'name' : event.currentTarget.name,
435 'filePath' : getFolderPath() + '/' + event.currentTarget.name,
436 'size' : event.currentTarget.size,
437 'creationDate' : event.currentTarget.creationDate,
438 'modificationDate' : event.currentTarget.modificationDate,
439 'type' : event.currentTarget.type
440 },
441 escape(event.data),{
442 'fileCount' : (fileQueue.length-1),
443 'speed' : kbsAvg
444 });
445 filesUploaded++;
446 fileQueue.splice(getIndex(ID),1);
447 delete activeUploads[ID];
448 if (!single) {
449 uploadify_uploadFiles(null, true);
450 }
451 event.currentTarget.removeEventListener(DataEvent.UPLOAD_COMPLETE_DATA, fileCompleteHandler);
452 if (!fileQueue.some(queueIsNotEmpty) && objSize(activeUploads) == 0) {
453 $trigger('uploadifyAllComplete',{
454 'filesUploaded' : filesUploaded,
455 'errors' : errors,
456 'allBytesLoaded' : allBytesLoaded,
457 'speed' : allKbsAvg
458 });
459 resetVars();
460 }
461 }
462
463 // Add all the event listeners
464 file.addEventListener(Event.OPEN, fileOpenHandler);
465 file.addEventListener(ProgressEvent.PROGRESS, fileProgressHandler);
466 file.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, fileCompleteHandler);
467
468 // Reset all the numbers
469 function resetVars() {
470 filesUploaded = 0;
471 errors = 0;
472 allBytesLoaded = 0;
473 allBytesTotal = 0;
474 allKbsAvg = 0;
475 filesChecked = 0;
476 queueReversed = false;
477 }
478
479 // Handle all the errors
480 file.addEventListener(HTTPStatusEvent.HTTP_STATUS, function(event:HTTPStatusEvent):void {
481 if (errorArray.indexOf(ID) == -1) {
482 $trigger('uploadifyError',ID,event.currentTarget,{
483 'type' : 'HTTP',
484 'info' : event.status
485 });
486 finishErrorHandler(ID);
487 }
488 });
489 file.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent):void {
490 if (errorArray.indexOf(ID) == -1) {
491 $trigger('uploadifyError',ID,event.currentTarget,{
492 'type' : 'IO',
493 'info' : event.text
494 });
495 finishErrorHandler(ID);
496 }
497 });
498 file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(event:SecurityErrorEvent):void {
499 if (errorArray.indexOf(ID) == -1) {
500 $trigger('uploadifyError',ID,event.currentTarget,{
501 'type' : 'Security',
502 'info' : event.text
503 });
504 finishErrorHandler(ID);
505 }
506 });
507
508 // Common routines used by all errors
509 function finishErrorHandler(ID:String) {
510 errorArray.push(ID);
511 fileQueue[getIndex(ID)].file = '';
512 delete activeUploads[ID];
513 if (!single) {
514 uploadify_uploadFiles(null, true);
515 }
516 errors++;
517 if (!fileQueue.some(queueIsNotEmpty)) {
518 if (root.hasEventListener(Event.ENTER_FRAME)) {
519 root.removeEventListener(Event.ENTER_FRAME, uploadCounter);
520 }
521 $trigger('uploadifyAllComplete',{
522 'filesUploaded' : filesUploaded,
523 'errors' : errors,
524 'allBytesLoaded' : allBytesLoaded,
525 'speed' : allKbsAvg
526 });
527 resetVars();
528 }
529 }
530
531 if (param.sizeLimit && file.size > parseInt(param.sizeLimit)) {
532 if (errorArray.indexOf(ID) == -1) {
533 $trigger('uploadifyError',ID,file,{
534 'type' : 'File Size',
535 'info' : param.sizeLimit
536 });
537 finishErrorHandler(ID);
538 }
539 } else {
540 file.upload(scriptURL, param.fileDataName);
541 activeUploads[ID] = true;
542 }
543 }
544
545 function uploadify_cancelFileUpload(ID:String, single:Boolean, clearFast:Boolean):void {
546 var index:int = getIndex(ID);
547 var fileObj:Object = new Object();
548 if (fileQueue[index].file) {
549 fileObj = fileQueue[index].file;
550 fileQueue[index].file.cancel();
551 allBytesTotal -= fileQueue[index].file.size;
552 }
553
554 fileQueue.splice(index,1);
555
556 if (activeUploads[ID]) {
557 delete activeUploads[ID];
558 uploadify_uploadFiles(null, true);
559 if (root.hasEventListener(Event.ENTER_FRAME) && objSize(activeUploads) == 0) {
560 root.removeEventListener(Event.ENTER_FRAME, uploadCounter);
561 }
562 }
563
564 $trigger('uploadifyCancel',ID,fileObj,{
565 'fileCount' : (fileQueue.length),
566 'allBytesTotal' : allBytesTotal
567 },clearFast);
568 }
569
570 // Cancel all uploads
571 function uploadify_clearFileUploadQueue(clearFast:Boolean):void {
572 if (!queueReversed) {
573 fileQueue.reverse();
574 queueReversed = true;
575 }
576 for (var n:Number = fileQueue.length - 1; n >= 0; n--) {
577 uploadify_cancelFileUpload(fileQueue[n].ID, false, clearFast);
578 }
579 if (root.hasEventListener(Event.ENTER_FRAME)) {
580 root.removeEventListener(Event.ENTER_FRAME, uploadCounter);
581 }
582 $trigger('uploadifyClearQueue');
583 filesUploaded = 0;
584 errors = 0;
585 allBytesLoaded = 0;
586 allBytesTotal = 0;
587 allKbsAvg = 0;
588 filesChecked = 0;
589 queueReversed = false;
590 }
591
592 // Create all the callbacks for the functions
593 ExternalInterface.addCallback('updateSettings', uploadify_updateSettings);
594 ExternalInterface.addCallback('startFileUpload', uploadify_uploadFiles);
595 ExternalInterface.addCallback('cancelFileUpload', uploadify_cancelFileUpload);
596 ExternalInterface.addCallback('clearFileUploadQueue', uploadify_clearFileUploadQueue);
597
598

       现在我们能够得出这样一个结论:Uploadify本质上是一个基于Flash的jQuery上传插件.那么它到底能不能跨域呢?这里我们要考虑两个安全模型.一个是浏览器的同源策略,jQuery与目标服务器的交互是过Jsonp方式来实现回避浏览器的同源策略。还有一个就是Flash的安全沙箱,分析之前我们还是先完成金色海洋想要的实验.

 

环境准备

       我们在IIS中部署两个站点,既然是验证跨域我们为这两个站点绑定主机头;

   站点A:www.a.com 端口83 站点B:www.b.com 端口84

  

   修改Host文件(文件位置c:\Windows\System32\drivers\etc\hosts)

 

127.0.0.1 www.a.com

 

127.0.0.1 www.b.com

   注意:为了避免偶然因素的影响,后面每一次修改之后我都会重启IIS,使用新的浏览器窗口进行测试。


  1. 首先验证两个站点是否正常运行:站点A使用'script': 'http://www.a.com:83/Uploader.ashx', 站点B使用'script': 'http://www.b.com:84/Uploader.ashx',即当前域页面上传到当前域.测试通过
  2. 将站点A上传的目标服务域修改成站点B,即修改'script': 'http://www.b.com:84/Uploader.ashx',测试结果见下面的截图

 

error 

    3.看到上面的Security Error了么,我们通过在站点B下面添加一个crossdomain.xml,该文件的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"
>
<cross-domain-policy>
<site-control permitted-cross-domain-policies="all" />
<allow-access-from domain="*" />
<allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>

 


   添加了这个文件之后,站点A上传文件到站点B成功!


Uploadify跨域原理

      上面通过添加了crossdomain.xml之后就实现了跨域上传文件,关键点在于Flash的安全沙箱策略;Flash安全策略简单讲:同一个域的属于同一个沙箱,同一个沙箱的可以互相访问.如果要访问另外一个沙箱的内容就要在另外一个沙箱定义信任,这种信任策略就定义在crossdomain.xml中。在我们的实验中就是在站点B的策略文件crossdomain.xml中定义了对站点A的信任,只不过我偷懒让站点B信任所有外部域名的访问。

     对于crossdomain.xml还有两点细节:1.这个文件的要放在站点的根目录下而且文件名固定 2.跨域访问端口在1024以下必须要通过策略文件来定义信任关系。换句话说端口大于等于1024隐式开放访问权限。策略文件的详细说明请点击这里查看。

 

总结   

    对于金色海洋的问题解答:之所以你可以上传到另外一个端口的站点时因为IP一样,如果是上传到另外一个域名下,需要再目标服务器的根目录下添加Flash安全策略文件.

     Uploadify本质上是一个基于Flash的jQuery上传插件.跨域上传的情况牵扯到两个安全模型,一个使浏览器的同源策略,一个使是Flash的安全沙箱策略;我们组合使用jQuery的Jsonp和策略文件实现了跨域上传.

     好吧,就到这里,周末愉快

 

     测试文件下载:Web1.rar crossdomain.xml