回头再说:Uploadify跨域上传原理


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

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

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

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

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

'script': '/_CommonPage/UploadHandler.<wbr></wbr>ashx',

改成

'script': 'http://192.168.0.1:8002/_<wbr></wbr>CommonPage/UploadHandler.ashx'<wbr></wbr>,

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

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

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

我给出的错误解释

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

Uploadify工作机制

我在VS2010里面新建了一个webApplicatio<wbr></wbr>n,在页面上使用Uploadify,页面代码如下:

 
 
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->

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

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

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

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

ContractedBlock.gif ExpandedBlockStart.gif uploadify.fla
 
  
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 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 {
17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值