将一个POST请求中的两个文件上传到rails服务器

时间:2011-03-17 12:15:22

标签: ruby-on-rails flex mime

我有一个flex应用程序想要在同一个POST请求中将两个图像上传到rails服务器。我想我正在创建POST请求的数据部分,但我不确定。当我打印导轨侧面的参数时,我只看到一个文件。

public class MultipartDataHandler extends EventDispatcher
{
    //<net:URLLoader id="loader" complete="completeHandler(event)" dataFormat="binary"  />
    private var loaderContext:LoaderContext = new LoaderContext(true);
    private var loader:URLLoader = new URLLoader();

    public function MultipartDataHandler()
    {
    }

    public function sendToServer(exteriorBitmapData:BitmapData, interiorBitmapData:BitmapData):void {
        var xml_file:String = UserPreference.getInstance().toXML().toXMLString(); 
        var gongos_id:int = UserPreference.getInstance().gongosId;
        var room_id:int = UserPreference.getInstance().roomId;
        var car_id:int = UserPreference.getInstance().theCar.id;

        // 1. Encode image as a png

        //          var bitmap:Bitmap = image.content as Bitmap;
        //          var bytes:ByteArray = pngEncoder.encode(bitmap.bitmapData);

        var pngEncoder:PNGEncoder = new PNGEncoder();
        var exteriorBytes:ByteArray = pngEncoder.encode(exteriorBitmapData);
        var interiorBytes:ByteArray = pngEncoder.encode(interiorBitmapData);

        // 2. Create multip part request
        var boundary:String = '------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7';
        var url:String = UserPreference.urlize("/cars/upload.xml");
        var request: URLRequest = new URLRequest(url);
        request.data = getMultiPartRequestData(boundary, 'car', exteriorBytes, interiorBytes, xml_file, gongos_id, room_id, car_id);
        request.method = URLRequestMethod.POST;
        request.contentType = "multipart/form-data; boundary=" + boundary; 

        // 3. Send to Server
        loader.load(request);
        loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
        loader.addEventListener(Event.COMPLETE, loaderCompleteHandler);

    }

    private function getMultiPartRequestData(boundary:String, resourceName:String, 
                                             exteriorBytes:ByteArray, 
                                             interiorBytes:ByteArray,
                                             xml_file:String, 
                                             gongos_id:int, room_id:int, car_id:int):ByteArray {
        var lf:String = "\r\n";
        var part1:String =  '--' + boundary + lf + 
            'Content-Disposition: form-data; name="Filename"' + lf + lf +
            '{0}' + lf +
            '--' + boundary + lf +
            'Content-Disposition: form-data; name="{1}[xml]"' + lf + lf +  
            '{2}' + lf + 
            '--' + boundary + lf + 
            'Content-Disposition: form-data; name="gongos_id"' + lf + lf +  
            '{3}' + lf + 
            '--' + boundary + lf + 
            'Content-Disposition: form-data; name="room_id"' + lf + lf +  
            '{4}' + lf + 
            '--' + boundary + lf + 
            'Content-Disposition: form-data; name="car_id"' + lf + lf +  
            '{5}' + lf + 
            '--' + boundary + lf + 
            'Content-Disposition: form-data; name="{1}[photo]"; ' +
            'filename="{0}"' + lf +
            'Content-Type: application/octet-stream' + lf +lf;
        var part2:String = '--' + boundary + lf + 
            'Content-Disposition: form-data; name="{1}[interior_photo]"; ' +
            'filename="{0}"' + lf +
            'Content-Type: application/octet-stream' + lf +lf;
        var part3:String =  '--' + boundary + lf +
            'Content-Disposition: form-data; name="Upload"' + lf + lf +
            'Submit Query' + lf +
            '--' + boundary +  '--';

        part1 = StringUtil.substitute(part1, 'car.png', resourceName, 
            xml_file, gongos_id, room_id, car_id);
        part2 = StringUtil.substitute(part2, 'interior.png', resourceName);


        var result:ByteArray = new ByteArray();
        result.writeMultiByte(part1, "ascii");
        result.writeBytes(exteriorBytes, 0, exteriorBytes.length)
        result.writeMultiByte(part2, "ascii");
        result.writeBytes(interiorBytes, 0, interiorBytes.length)
        result.writeMultiByte(part3, "ascii");

        trace(part1 + "EXTERIOR BYTES" + part2 + "INTERIOR BYTES" + part3);
        return result;
    }

}

}

这是调试控制台打印的内容。请注意,我不会在控制台中打印实际字节,因为这会非常痛苦,但您可以看到它们的去向。

--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Filename"

car.png
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="car[xml]"

<creation>
  <car>
    <bodyId>1</bodyId>
    <themeId>0</themeId>
    <roomId>0</roomId>
    <userId>0</userId>
    <name>null</name>
    <exterior/>
    <interior/>
  </car>
</creation>
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="gongos_id"

0
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="room_id"

1
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="car_id"

0
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="car[photo]"; filename="car.png"
Content-Type: application/octet-stream

EXTERIOR BYTES--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="car[interior_photo]"; filename="interior.png"
Content-Type: application/octet-stream

INTERIOR BYTES--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Upload"

Submit Query
--------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--

最后,这就是Rails所说的。

--- !map:HashWithIndifferentAccess 
room_id: "1"
Filename: car.png
format: xml
action: upload
car_id: "0"
controller: cars
car: !map:HashWithIndifferentAccess 
  photo: !ruby/object:File {}

  xml: |-
    <creation>
      <car>
        <bodyId>1</bodyId>
        <themeId>0</themeId>
        <roomId>0</roomId>
        <userId>0</userId>
        <name>null</name>
        <exterior/>
        <interior/>
      </car>
    </creation>
gongos_id: "0"
Processing CarsController#upload to xml (for 127.0.0.1 at 2011-03-17 08:05:00) [POST]
  Parameters: {"Filename"=>"car.png", "room_id"=>"1", "car_id"=>"0", "car"=>{"photo"=>#<File:/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/RackMultipart20110317-24400-14hcvab-0>, "xml"=>"<creation>\n  <car>\n    <bodyId>1</bodyId>\n    <themeId>0</themeId>\n    <roomId>0</roomId>\n    <userId>0</userId>\n    <name>null</name>\n    <exterior/>\n    <interior/>\n  </car>\n</creation>"}, "gongos_id"=>"0"}
[paperclip] identify '-format' '%wx%h' '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0.png[0]' 2>/dev/null
[paperclip] convert '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0.png[0]' '-resize' '500x500>' '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0,24400,0' 2>/dev/null
[paperclip] identify '-format' '%wx%h' '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0.png[0]' 2>/dev/null
[paperclip] convert '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0.png[0]' '-resize' '250x250>' '/var/folders/f6/f6zP-E52HiaycvHwz90OtE+++TI/-Tmp-/stream,24400,0,24400,1' 2>/dev/null
  User Load (0.3ms)   SELECT * FROM "users" WHERE ("users"."gongos_id" = '0' AND "users"."room_id" = '1') LIMIT 1
  Car Create (81.1ms)   INSERT INTO "cars" ("name", "interior_photo_file_name", "room_id", "photo_file_size", "interior_photo_file_size", "interior_photo_updated_at", "created_at", "xml", "photo_file_name", "updated_at", "body_id", "photo_content_type", "deleted", "user_id", "interior_view_id", "theme_id", "photo_updated_at", "parent_car_id", "interior_photo_content_type") VALUES('Faxo', NULL, NULL, 102547, NULL, NULL, '2011-03-17 12:05:03', '<creation>
 <car>
 <bodyId>1</bodyId>
 <themeId>0</themeId>
 <roomId>0</roomId>
 <userId>0</userId>
 <name>null</name>
 <exterior/>
 <interior/>
 </car>
</creation>', 'car.png', '2011-03-17 12:05:03', 1, 'application/octet-stream', NULL, NULL, NULL, 0, '2011-03-17 12:05:01', NULL, NULL)
[paperclip] Saving attachments.
[paperclip] saving /Users/glurban/code/amfdreamcar/public/system/photos/18/medium/car.png
[paperclip] saving /Users/glurban/code/amfdreamcar/public/system/photos/18/original/car.png
[paperclip] saving /Users/glurban/code/amfdreamcar/public/system/photos/18/thumb/car.png
[paperclip] Saving attachments.
Rendering cars/upload
Completed in 2750ms (View: 60, DB: 81) | 200 OK [http://localhost/cars/upload.xml]

所以,正如你所看到的,只有一张照片(第一张)似乎出现在参数中。切换订单只会显示interior_photo。我做错了什么?

我还尝试将两个单独的调用链接在一起,但由于Flash 10的安全限制而导致文件上传失败,而用户无需执行操作(例如单击按钮)。我甚至尝试将loader.load()的两个调用放在同一个函数中,使用随机数生成器在flex端创建一个id(因为rails需要知道这两个调用是针对同一辆汽车的,并且没有链接我不能使用第一次调用的响应来传回汽车ID),但我遇到了竞争条件,第二次调用以某种方式在第一次调用之前到达服务器。 Adobe安全... FFFFFFFUUUUUU。

1 个答案:

答案 0 :(得分:0)

天啊。

花了3个小时解决这个问题(调试,尝试其他失败的解决方案等)。

然后,在我发布之后,我意识到了这个问题: 换行将是我的死亡。将lf添加到part2和part3的前面,我们很好。

:o