Wysyłanie formularzy multipart/form-data
8 Wrzesień 2009 – 14:08Trafiłem ostatnio na dość dziwny problem. Potrzebowałem mianowicie wysłać z poziomu Flexa dane formularza, które po stronie serwera zostałyby odebrane przez PHP (lub inny język server-side).
Jednak cały kłopot polegał na tym, że:
- dane te miały wykorzystać istniejący już kod obsługiwany przez formularz w HTML’u – czyli niejako miałem się podszyć pod zwykłą stronę www, nie wykorzystując żadnych udogodnień typu AMF, Webservice czy RemoteObject,
- chciałem wysłać jednocześnie dane tekstowe (np. dane rejestracyjne) oraz binarne (np. obrazki JPG), bez limitu ilości,
- obrazki nie były pobierane z dysku użytkownika przez FileReference.browse, ale tworzone w locie jako zrzuty komponentów przez ImageSnapshot i trzymane w pamięci w zmiennych typu ByteArray.
Jedyne co udało mi się znaleźć to artykuł na blogu Neer’a Friedman’a i jego projekt na Google Code. Był to dobry początek do zmian…
BTW: niejaki Mike Stead, którego komentarz widnieje pod wpisem Neer’a też zajmował się tym problemem i zdaje się, że nawet go jakoś elegancko rozwiązał, jednak jego stronka padła kompletnie i nie ma jej nawet w Google Cache…
Wywaliłem kod odpowiedzialny za używanie Socketów zamieniając go na zwykłego URLLoader’a oraz troche zrefaktoryzowałem kod (uporzadkowałem). Tym sposobem pojawiła się biblioteka MultipartRequestLoader
Przykładowa aplikacja (wraz z kodem źródłówym pod prawym klikiem myszki), a tutaj kod biblioteki: multipart_loader_imrahil.zip
Kod przykładowej aplikacji:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()" viewSourceURL="srcview/index.html"> <mx:Script> <![CDATA[ import multipart.MultipartVariables; import multipart.MultipartRequestLoader; private var loader:MultipartRequestLoader; private function init():void { loader = new MultipartRequestLoader('http://flex.imrahil.com/work/multipart_loader/upload.php'); var variables:MultipartVariables = new MultipartVariables(); var myByteArray:ByteArray = new ByteArray(); // we will create a fake file content here, you should replace this with the binary data you want to upload for(var i:int=0; i<100;i++) { myByteArray.writeUTFBytes("123by\nAR\r\nRA\x65\x0156"); } variables.add('file_data', myByteArray, 'filename.bin'); variables.add('another_var','extra data'); loader.variables = variables; loader.addEventListener(Event.COMPLETE, fileUploaded); loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); loader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); } private function fileUploaded(event:Event):void { outputTxt.text += 'Result:'; outputTxt.text += MultipartRequestLoader(event.target).responseBody; } private function securityErrorHandler(event:SecurityErrorEvent):void { outputTxt.text = "securityErrorHandler: " + event; } private function ioErrorHandler(event:IOErrorEvent):void { outputTxt.text = "ioErrorHandler: " + event; } private function upload(event:MouseEvent):void { loader.load(); } ]]> </mx:Script> <mx:VBox width="100%" height="100%" horizontalAlign="center" verticalAlign="middle"> <mx:Button label="Upload!" click="upload(event)" /> <mx:TextArea id="outputTxt" width="500" height="250" /> </mx:VBox> </mx:Application> |