Uploadify跨域上传原理

引用:http://www.cnblogs.com/me-sa/archive/2010/05/21/How-Uploadify-Cross-Domain.html

《 回头再说: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,页面代码如下:

 1 <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
 2     <script src="Scripts/jquery.uploadify.v2.1.0.js" type="text/javascript"></script>
 3     <script src="Scripts/swfobject.js" type="text/javascript"></script>
 4     <script type="text/javascript">
 5        // <![CDATA[
 6         var id = "55";
 7         var theString = "asdf";
 8         $(document).ready(function () {
 9             $(‘#fileInput‘).uploadify({
10                 ‘uploader‘: ‘uploadify.swf‘,
11                 ‘script‘: ‘http://www.b.com:84/Uploader.ashx‘,
12                 ‘scriptData‘: { ‘id‘: id, ‘foo‘: theString },
13                 ‘cancelImg‘: ‘cancel.png‘,
14                 ‘auto‘: true,
15                 ‘multi‘: true,
16                 ‘fileDesc‘: ‘Image Files‘,
17                 ‘fileExt‘: ‘*.jpg;*.png;*.gif;*.bmp;*.jpeg‘,
18                 ‘queueSizeLimit‘: 90,
19                 ‘sizeLimit‘: 4000000,
20                 ‘buttonText‘: ‘Choose Images‘,
21                 ‘folder‘: ‘/uploads‘,
22                 ‘onAllComplete‘: function (event, queueID, fileObj, response, data) {
23
24                 }
25             });
26         });
27    // ]]></script>
28
29    <input id="fileInput" name="fileInput" type="file" />

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

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


1

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

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

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

现在我们能够得出这样一个结论: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‘,测试结果见下面的截图

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

时间: 2024-10-12 03:37:27

Uploadify跨域上传原理的相关文章

跨域上传文件(还是没有明白)

转: 最近工作中有这样的需求:项目在A机器(假设域名为www.a.com)上跑,资源文件要存储在专门的资源机器B(假设域名为www.b.com),要求在A上传文件到B上同时将上传信息以json格式返回. 由于之前的项目都比较小,也没有这样的需求,基本都是在单机上操作,自然涉及不到跨域的问题,初次遇到这个问题,比较棘手,进行了如下尝试均失败. 尝试一:在A机器上的页面中嵌入一个iframe,iframe的src指向B机器的一个上传页面,这样可以很容易将资源上传到B机器,但是却很难实现“以json格

Js 跨域上传文件

代码在github上( https://github.com/andygithubchen/jsUpload ),请结合github上的文件阅读. 主要实现js跨域上传文件,这里的跨域目前只在两个域名所指向的服务器在同一局域网内. 当然,这两种方案都可以做同域名上传. 例如: 192.168.1.60 www.test.cn 192.168.1.61 www.video.cn 如果要在www.test.com域名下上传文件到www.video.com域名下,可以使用下面这两个方案: 方案一(在s

ie8、9跨域上传文件(图片)

前言:新的项目,需要将图片跨域上传到专门的图片服务器上面,而且还要支持ie8/9的跨域上传. 解决:为了解决这个方案踩了很多坑,特此记录.以前收集了一些上传的组件 文件(图片)上传组件 ,各有优劣. 1:因为google在将来的版本不在支持flash了,所以不想使用swf支撑的组件上传 2:尝试了AjaxFileUpload 组件,这个在google跨域直接挂掉了. 3:尝试百度的上传组件,Web Uploader 这个挺不错,支持跨域,但是ie8/9跨域支持不大好,只好放弃了(也有可能是我没有

跨域通信/跨域上传浅析

web项目跨域问题主要包括跨域通信和跨域上传,下面对这两方面分别做一个分析,具体项目中用哪个方案要看项目具体需求. 跨域通信 jsonp hash server proxy window.name cors postmessage redirect jsonp 原理:发起一个GET请求,回调函数带到请求参数中,把数据发送过去 坏处:服务器需要支持jsoncallback参数 好处:业界比较通用的方案,包括打点等操作都可以用类似技术 浏览器支持:chrome/firefox/safari/oper

Ueditor1.4.3实现跨域上传到独立文件服务器,完美解决单文件和多文件上传!

再写配置方法之前先吐槽一下网上的各种教程,TM没一个有卵用,一群傻屌不会写就别写,写了就要负责. 百度google搜了半天,全是配置什么document.domain,根域名什么的,我只想对你说: 好了,talk is cheap show me the code,言归正传: 首先去ue官网下载1.43版 .net版本,解压之后,把demo文件夹改成web,把net那个文件夹拷贝出来放到web外面,如图: 这样就把编辑器的静态文件和动态文件分离了,动态部分放到文件服务器上,静态部分集成到我们的网

h5 文件跨域上传

var imgUrl = "http://www.xxx.xxxxx.xxxx";$.ajax({ url:imgUrl, type: 'POST', crossDomain: true, jsonp: "jsoncallback", data: formData, contentType: false, //必须 processData: false, //不能用success,否则不执行 complete: function (data) { var data 

从Ueditor跨域上传,总结的一次跨域上传的爬坑经历

项目内其中一个管理后台需要发布文章,需要一个富文本编辑器,经过一番选择后,最终选择了百度的Ueditor. 由于上传的文件是上传到另一台专门存放图片等静态资源的服务器上面的,所以就涉及到了跨域上传. 我实现跨域上传的主要方式是将编辑器的前后端分离,前段直接放到需要用的项目内,接收上传的后端(已做权限验证)放到图片服务器上面. 跨域要添加两个HTTP头: Access-Control-Allow-Origin: *//允许任意域名发起的跨域请求Access-Control-Allow-Header

asp.net mvc 文件跨域上传,接收返回结果

在系统中我们可能有各种各样的文件上传,这样我们可能会把文件模块单独部署一台服务器,这样在上传时就会遇到跨域问题.我们可以先上传到服务端然后通过httpClient等技术再上传到文件服务器,这样就不会存在跨域问题,但是这样多出了服务器中转的一个步骤,现在我们说一下如何在客户端直接跨域上传到文件服务器. 1.文件服务器部署一个文件上传接口(实现技术:webapi,webservice,mvc等等) 文件上传接口示例如下(MVC方式): /// <summary> /// 上传接口 /// <

解决使用elementUI框架el-upload跨域上传时session丢失问题

解决方法一: 1.使用elementUI框架el-upload跨域上传时,后端获取不到cookie,后端接口显示未登录,在添加了 with-credentials="true"后依然不生效 前端会报上面的错误,解决方式:后端把把*号改成httpServletRequest.getHeader("Origin") 解决方法二: 1.把config目录下的index.js文件打开,修改proxyTable属性的设置: 考虑到这个这个目标路径可能需要修改,所以打包后需要单