Recentemente ho dovuto implementare l'upload di file a una servlet con Adobe Flex. Poiché ho incontrato alcuni ostacoli ho deciso di postare la soluzione a cui sono arrivato, nell'eventualità che sia utile ad altri nella stessa situazione.
Come primo tentativo ho usato il metodo "canonico", ovvero chiamare il metodo
upload
di
FileReference.
Nella risposta della servlet era immersa una rassicurante scritta -
"file uploaded" - ma il file caricato risultava irreperibile.
Dopo una verifica con
firebug ho scoperto che nella richiesta non veniva inviata la JSESSIONID, necessaria al server per identificare la sessione in cui viene fatto l'upload.
Poco male, visto che basta appendere all'URL di richiesta la stringa ";jsessionid=", seguita dalla ID.
Il problema è che bisogna modificare l'interfaccia web per recuperare in qualche modo questa ID.
Come se non bastasse l'applicazione flash si blocca fino a che l'upload non è completato, e questo non è un bene. Tra l'altro, per file di dimensione superiore a qualche kilobyte, viene bloccato tutto il browser, con un consumo esorbitante di memoria RAM.
Questo evidentemente è dovuto a un memory leak nel Flash Player, e accade sia con Firefox che con Chrome che con Opera.
Scartata questa soluzione, quando ormai mi stavo convincendo ad usare una "pezza" AJAX, mi sono rituffato in Google, e mi sono imbattuto in una comoda classetta ActionScript,
MultipartURLLoader, che costruisce correttamente la richiesta HTTP per l'upload contemporaneo di più file.
Ho quindi dovuto commentare alcune linee (in particolare la 374 e quelle dalla 408 alla 417) per adattarla al mio caso di file singolo.
Per poter usare questa classe è necessario usare il caricamento di file locali, una caratteristica introdotta con la versione 10 del Flash Player, mediante il metodo
load
di FileReference, chiamato nel gestore dell'evento SELECT:
/* in constructor or wherever you want */
fileRef.addEventListener( Event.SELECT,
fileSelected );
fileRef.addEventListener( Event.COMPLETE,
loadComplete );
...
/* in fileSelected() */
fileRef.load();
Quando il file è caricato in memoria viene chiamato il gestore
loadComplete()
, nel quale possiamo iniziare l'upload:
private var multipartLoader:MultipartURLLoader =
new MultipartURLLoader();
...
var loader:URLLoader =
multipartLoader.loader;
loader.addEventListener(Event.COMPLETE,
uploadComplete);
loader.addEventListener(
ProgressEvent.PROGRESS,
progressHandler);
...
multipartLoader.addFile(fileRef.data,
fileRef.name,
"file",
"application/octet-stream");
multipartLoader.load(urlString);
Una volta completato l'upload il gestore
progressHandler()
comincerà ad essere chiamato, fino allo scaricamento completo della risposta, che coinciderà con l'invocazione del gestore
uploadComplete()
.
E questo è tutto!
Happy Flexing!