【问题标题】:Error #2044: Unhandled IOErrorEvent:. text=Error #2038: File I/O Error错误 #2044:未处理的 IOErrorEvent:。文本=错误 #2038:文件 I/O 错误
【发布时间】:2013-08-11 22:56:01
【问题描述】:

我有一个在 Flash 或 Flash Builder 4.5 上编译的标准 AIR 脚本,旨在将文件上传到 php 服务器端代码。在完成请求之前,代码首先将文件写入用户桌面。

import flash.net.*;
import flash.filesystem.*

//create the file
var file:File = File.desktopDirectory;
file = file.resolvePath("test.txt");
var fs:FileStream = new FileStream();
fs.open(file, FileMode.WRITE);
//write "test" to txt file
fs.writeUTFBytes("test");
fs.close();

//start request
var req:URLRequest = new URLRequest();
req.method = "POST";
req.url = //php file
var vars:URLVariables = new URLVariables();
vars.a = 1;
vars.b = 2;
vars.c = 3
req.data = vars;
file.upload(req, "txt_file");

现在,当我在 localhost (XAMPP) 上我自己的 Apache 测试服务器上上传到一个 php 文件时,文件上传会顺利进行,没有任何错误。但是,当我尝试上传到我的实际服务器时,我收到一个 I/O 错误:

错误 #2044:未处理的 IOErrorEvent:。文本=错误 #2038:文件 I/O 错误。

我检查了我的 max_file_size 设置为 2MB,所以这不是问题。网址也是正确的。查看其他来源(例如http://www.judahfrangipane.com/blog/2007/01/01/error-2044-unhandled-ioerrorevent-texterror-2038-file-io-error/),一些人认为问题出在 Apache ModSecurity,通过将目录的 .htaccess 设置为:

SecFilterEngine Off
SecFilterScanPOST Off

这不起作用。事实上,它使我设计用于从同一服务器获取数据的其余代码过时了。我也知道这不是跨域问题。我也尝试将 php 代码设置为返回 HTTP 200。仍然无法正常工作。有些人认为这些错误有点随机,并且无论错误如何,实际文件上传都是发生的。因此,只需捕获错误并忽略它(http://dev.nuclearrooster.com/2008/04/05/uploading-with-a-filereference-from-flex-3-on-os-x/),就可以解决问题。这对我来说不是一个选项,因为我需要跟踪上传进度。

有趣的是,这似乎是 Mac OSX 问题,因为我在 Windows 编译器上运行的确切脚本没有错误,尽管唯一的规定是它们是使用旧版本的 AIR 制作的。所以我不确定这里是否是这种情况。

我已经用头撞墙 3 天了。请帮帮我......

更新

刚刚发现我的文件上传到的服务器正在对文件上传请求返回 HTTP 301 响应,这种情况再次仅发生在 AIR 上的 OSX 上,而不是 Windows 或通过 Firefox 提交的表单数据上。

【问题讨论】:

    标签: actionscript-3 flash air flash-builder


    【解决方案1】:

    好的。这绝对似乎是 Mac OSX 的问题。出于某种原因,OSX 中 File.upload() 方法创建的 HTTP 标头会导致外部服务器崩溃,并出现 301 Move Permanently。这不会在 Windows 中发生。当然,就 AIR 编译器而言,除了 HTTP 2xx 响应之外的任何响应都会导致 I/O 错误。因此,为了解决文件上传问题,我们必须手动创建负责上传的 HTTP 标头本身。我建议在此问题解决之前不要使用File.upload()(或FileReference.upload())。

    为此,我们上传的文件必须转换为 ByteArray。因此我只会使用 File/FileReference 来捕获文件。实际上传时,必须将文件转换为ByteArray

    在我上面的例子中,很简单:

    import flash.net.*
    import flash.utils.ByteArray;
    
    var xml:XML = new XML(<items><item>one</item><item>two</item></items>);
    var data:ByteArray = new ByteArray();
    data.writeUTF(xml.toXMLString());
    

    现在就创建手动 HTTP 标头而言,这要归功于 Jonathan Marston (http://marstonstudio.com/2007/10/19/how-to-take-a-snapshot-of-a-flash-movie-and-automatically-upload-the-jpg-to-a-server-in-three-easy-steps/) 和他漂亮的 UploadPostHelper 类:

    package {
    
        import flash.events.*;
        import flash.net.*;
        import flash.utils.ByteArray;
        import flash.utils.Endian;
    
        /**
         * Take a fileName, byteArray, and parameters object as input and return ByteArray post data suitable for a UrlRequest as output
         *
         * @see http://marstonstudio.com/?p=36
         * @see http://www.w3.org/TR/html4/interact/forms.html
         * @see http://www.jooce.com/blog/?p=143
         * @see http://www.jooce.com/blog/wp%2Dcontent/uploads/2007/06/uploadFile.txt
         * @see http://blog.je2050.de/2006/05/01/save-bytearray-to-file-with-php/
         *
         * @author Jonathan Marston
         * @version 2007.08.19
         *
         * This work is licensed under a Creative Commons Attribution NonCommercial ShareAlike 3.0 License.
         * @see http://creativecommons.org/licenses/by-nc-sa/3.0/
         *
         */
        public class UploadPostHelper {
    
            /**
             * Boundary used to break up different parts of the http POST body
             */
            private static var _boundary:String = "";
    
            /**
             * Get the boundary for the post.
             * Must be passed as part of the contentType of the UrlRequest
             */
            public static function getBoundary():String {
    
                if(_boundary.length == 0) {
                    for (var i:int = 0; i < 0x20; i++ ) {
                        _boundary += String.fromCharCode( int( 97 + Math.random() * 25 ) );
                    }
                }
    
                return _boundary;
            }
    
            /**
             * Create post data to send in a UrlRequest
             */
            public static function getPostData(fileName:String, byteArray:ByteArray, parameters:Object = null):ByteArray {
    
                var i: int;
                var bytes:String;
    
                var postData:ByteArray = new ByteArray();
                postData.endian = Endian.BIG_ENDIAN;
    
                //add Filename to parameters
                if(parameters == null) {
                    parameters = new Object();
                }
                parameters.Filename = fileName;
    
                //add parameters to postData
                for(var name:String in parameters) {
                    postData = BOUNDARY(postData);
                    postData = LINEBREAK(postData);
                    bytes = 'Content-Disposition: form-data; name="' + name + '"';
                    for ( i = 0; i < bytes.length; i++ ) {
                        postData.writeByte( bytes.charCodeAt(i) );
                    }
                    postData = LINEBREAK(postData);
                    postData = LINEBREAK(postData);
                    postData.writeUTFBytes(parameters[name]);
                    postData = LINEBREAK(postData);
                }
    
                //add Filedata to postData
                postData = BOUNDARY(postData);
                postData = LINEBREAK(postData);
                bytes = 'Content-Disposition: form-data; name="Filedata"; filename="';
                for ( i = 0; i < bytes.length; i++ ) {
                    postData.writeByte( bytes.charCodeAt(i) );
                }
                postData.writeUTFBytes(fileName);
                postData = QUOTATIONMARK(postData);
                postData = LINEBREAK(postData);
                bytes = 'Content-Type: application/octet-stream';
                for ( i = 0; i < bytes.length; i++ ) {
                    postData.writeByte( bytes.charCodeAt(i) );
                }
                postData = LINEBREAK(postData);
                postData = LINEBREAK(postData);
                postData.writeBytes(byteArray, 0, byteArray.length);
                postData = LINEBREAK(postData);
    
                //add upload filed to postData
                postData = LINEBREAK(postData);
                postData = BOUNDARY(postData);
                postData = LINEBREAK(postData);
                bytes = 'Content-Disposition: form-data; name="Upload"';
                for ( i = 0; i < bytes.length; i++ ) {
                    postData.writeByte( bytes.charCodeAt(i) );
                }
                postData = LINEBREAK(postData);
                postData = LINEBREAK(postData);
                bytes = 'Submit Query';
                for ( i = 0; i < bytes.length; i++ ) {
                    postData.writeByte( bytes.charCodeAt(i) );
                }
                postData = LINEBREAK(postData);
    
                //closing boundary
                postData = BOUNDARY(postData);
                postData = DOUBLEDASH(postData);
    
                return postData;
            }
    
            /**
             * Add a boundary to the PostData with leading doubledash
             */
            private static function BOUNDARY(p:ByteArray):ByteArray {
                var l:int = UploadPostHelper.getBoundary().length;
    
                p = DOUBLEDASH(p);
                for (var i:int = 0; i < l; i++ ) {
                    p.writeByte( _boundary.charCodeAt( i ) );
                }
                return p;
            }
    
            /**
             * Add one linebreak
             */
            private static function LINEBREAK(p:ByteArray):ByteArray {
                p.writeShort(0x0d0a);
                return p;
            }
    
            /**
             * Add quotation mark
             */
            private static function QUOTATIONMARK(p:ByteArray):ByteArray {
                p.writeByte(0x22);
                return p;
            }
    
            /**
             * Add Double Dash
             */
            private static function DOUBLEDASH(p:ByteArray):ByteArray {
                p.writeShort(0x2d2d);
                return p;
            }
    
        }
    }
    

    现在,我们利用该类来使用旧的URLRequest 创建我们的 HTTP 标头:

    var req:URLRequest = new URLRequest();
    req.url = //server-side url (.php)
    req.contentType = "multipart/form-data; boundary=" + UploadPostHelper.getBoundary();
    req.method = URLRequestMethod.POST;
    //Be sure to place the actual file name with its extension as the file name. Set the second argument as the ByteArray created earlier. Any other parameters (name-value pairs) can be added via an optional third parameter (see class above)
    req.data = UploadPostHelper.getPostData("test.xml", data);
    req.requestHeaders.push(new URLRequestHeader("Cache-Control", "no-cache"));
    

    现在不再使用File.upload() 来完成请求,而是使用URLLoader

    var loader:URLLoader = new URLLoader();
    //We have to load the data as binary as well
    loader.dataFormat = URLLoaderDataFormat.BINARY;
    loader.addEventListener(Event.COMPLETE, complete);
    loader.addEventListener(IOErrorEvent.IO_ERROR, ioerror);
    loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, secerror);
    loader.load(req);
    
    //Event handlers
    function complete(e:Event):void {
        var ba:ByteArray = e.target.data;
        //Returns the XML data
        trace(ba.readUTF()); 
    }
    function ioerror(e:IOErrorEvent):void {}
    function secerror(e:SecurityErrorEvent):void {}
    

    而且一切都应该运行良好。就服务器端而言,文件名由上面的类定义为Filedata。用于捕获文件的简单 PHP 脚本如下所示:

    <?php
    echo file_get_contents($_FILES['Filedata']['tmp_name']);
    var_dump($_FILES['Filedata']);
    /*
    array(1) {
        ["Filedata"]=>array(5) {
            ["name"]=>string(8) "test.xml"
            ["type"]=>string(24) "application/octet-stream"
            ["tmp_name"]=>string(38) "root/tmp/php2jk8yk"
            ["error"]=>int(0)
            ["size"]=>int(58)
        }
    }
    */
    ?>
    

    【讨论】:

    • 这个变通办法的唯一问题是我们不能再跟踪现在跟踪下载进度的上传 ProgressEvent。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多