cycle.js, superagent, ファイルの送信でめっちゃハマった

問題

cycle.jsのcycle-http-driver(中はsuperagent)使ってて、ファイルを送信しようと思ったら、うまく行かなくて中々わからなかった。

解決

  1. superagentでのファイル送信はFormDataを使う(https://github.com/visionmedia/superagent/issues/746 )
  2. cycle-httpがsuperagentに渡すtypeをデフォルトで'json'にしてるので、明示的にnullにする必要がある。

typeに関して'form'などを設定するとboundaryがブラウザで設定されなくなる。

            .map(x => {
                var formData = new FormData();
                formData.append('file', x.files[0]);
                return formData;
            })
            .map(x => ({
                id: 'post-hoge',
                method: 'POST',
                url: '/hoge',
                send: x,
                type: null
            }));

以下、試行錯誤

lookupFileで取れる形式にしたい

postImportR :: Handler Value  
postImportR = do  
    mf <- lookupFile "file"

html formで送る

問題なく動く raw body

------WebKitFormBoundary0N1SwOCv3CEBDdB5\r\nContent-Disposition: form-data; name=\"file\"; filename=\"dump (5)\"\r\nContent-Type: application/octet-stream\r\n\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed\n xmlns=\"http://pur  
[中略]
eed>\n\r\n------WebKitFormBoundary0N1SwOCv3CEBDdB5--\r\n  

formData作って送ってみる

    .map(x => {
        var formData = new FormData();
        formData.append('key', "testvalue");
        formData.append('file', x.files[0]);
        return formData;
    })
            .map(x => ({
                id: 'post-import',
                method: 'POST',
                url: settings.API_BASE + '/import',
                send: x
            }));
raw body  
"------WebKitFormBoundaryUpbB3jqnnJAstRZp\r\nContent-Disposition: form-data; nam[略]Zp--\r\n"

attachしてみる

            .map(x => ({
                id: 'post-import',
                method: 'POST',
                url: settings.API_BASE + '/import',
                //              send: x,
                attach: [{name: 'file', path:x.files[0], filename: 'name'}],
                type: 'form'
            }));