2016-08-26 9 views
2

SITUATION終了:春に(ノードコアHTTPSモジュールを介して)のNode.jsからマルチパートフォーム要求を送信org.springframework.web.multipart.MultipartException:マルチパートサーブレット要求を解析できませんでした...ストリームが突然

-boot Java API。 APIは、2つのフォーム・データ要素を必要とします。

"ルート"
"ファイル"

FULL ERROR: Exception processed - Main Exception: org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: Stream ended unexpectedly

リクエストヘッダ:

{"Accept":"*/*", 
    "cache-control":"no-cache", 
    "Content-Type":"multipart/form-data; boundary=2baac014-7974-49dd-ae87-7ce56c36c9e7", 
    "Content-Length":7621} 

FORM-DATA BEING書面(すべてバイナリとして書かれている):

Content-Type: multipart/form-data; boundary=2baac014-7974-49dd-ae87-7ce56c36c9e7 

--2baac014-7974-49dd-ae87-7ce56c36c9e7 

Content-Disposition:form-data; name="route" 

...our route object 

--2baac014-7974-49dd-ae87-7ce56c36c9e7 
Content-Disposition:form-data; name="files"; filename="somefile.xlsx" 
Content-Type:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 

...excel file contents 

--2baac014-7974-49dd-ae87-7ce56c36c9e7-- 

NODEのCODE:

let mdtHttpMultipart = (options, data = reqParam('data'), cb) => { 
    const boundaryUuid = getUuid() 
    , baseHeaders = { 
     'Accept': '*/*', 
     'cache-control': 'no-cache' 
     } 
    , composedHeaders = Object.assign({}, baseHeaders, options.headers) 
    ; 

    options.path = checkPath(options.path); 

    let composedOptions = Object.assign({}, { 
    'host': getEdiHost(), 
    'path': buildPathFromObject(options.path, options.urlParams), 
    'method': options.method || 'GET', 
    'headers': composedHeaders, 
    'rejectUnauthorized': false 
    }); 


    composedOptions.headers['Content-Type'] = `multipart/form-data; boundary=${boundaryUuid}`; 

    let multipartChunks = []; 
    let dumbTotal = 0; 

    let writePart = (_, encType = 'binary', skip = false) => { 
    if (!_) { return; } 

    let buf = Buffer.from(_, encType); 
    if (!skip) {dumbTotal += Buffer.byteLength(buf, encType);} 
    multipartChunks.push(buf); 
    }; 

    writePart(`Content-Type: multipart/form-data; boundary=${boundaryUuid}\r\n\r\n`, 'binary', true) 
    writePart(`--${boundaryUuid}\r\n`) 
    writePart(`Content-Disposition:form-data; name="route"\r\n`) 
    writePart(JSON.stringify(data[0]) + '\r\n') 
    writePart(`--${boundaryUuid}\r\n`) 
    writePart(`Content-Disposition:form-data; name="files"; filename="${data[1].name}"\r\n`) 
    writePart(`Content-Type:${data[1].contentType}\r\n`) 
    writePart(data[1].contents + '\r\n') 
    writePart(`\r\n--${boundaryUuid}--\r\n`); 

    let multipartBuffer = Buffer.concat(multipartChunks); 

    composedOptions.headers['Content-Length'] = dumbTotal; 
    let request = https.request(composedOptions); 

    // on nextTick write multipart to request 
    process.nextTick(() => { 
    request.write(multipartBuffer, 'binary'); 
    request.end(); 
    }); 

    // handle response 
    request.on('response', (httpRequestResponse) => { 
    let chunks = [] 
     , errObject = handleHttpStatusCodes(httpRequestResponse); 
    ; 

    if (errObject !== null) { 
     return cb(errObject, null); 
    } 

    httpRequestResponse.on('data', (chunk) => { chunks.push(chunk); }); 
    httpRequestResponse.on('end',() => { 
     let responseString = Buffer.concat(chunks).toString() 
     ; 

     return cb(null, JSON.parse(responseString)); 
    }); 

    }); 

    request.on('error', (err) => cb(err)); 
}; 

我々は500が仕様に基づいてスローするために何らかの理由を見ることができません。ここでフォーマットを微妙に変えてみましたが、結果を正しく達成するにはまだありません。

サイドノート:これはPOSTMANを使用して私たちのために働いていますが、私たちの独自のアプリケーションサーバー(実際にはエクセルファイルを作成しています)を使って動作させることはできません。

お試しいただきたいアイデアがあれば助けてください。

+0

おそらくない問題が、あなたは' writePart(呼び出し初めて'composedOptions.headers ['Content-Type'] = ...'を指定すると、既にあなたのために追加されています。また、最後の ' - $ {boundaryUuid} - 'の前後で改行する必要はありません。 – idbehold

+0

これらの変更を行い、期待どおりの結果が得られました。 –

+0

'バイナリ'エンコーディングについては確かですか?これは 'latin1'のエイリアスです。すべての 'base64'エンコーディングが何か違いがあるかどうかを見てください。 –

答えて

2

このお試しください: `あなたはどのContent-Typeヘッダを追加している)

let mdtHttpMultipart = (options, data = reqParam('data'), cb) => { 
    const boundaryUuid = getUuid() 
    , baseHeaders = { 
     'Accept': '*/*', 
     'cache-control': 'no-cache' 
     } 
    , composedHeaders = Object.assign({}, baseHeaders, options.headers) 
    ; 

    let file = data[1] 
    let xlsx = file.contents 

    options.path = checkPath(options.path); 

    let composedOptions = Object.assign({}, { 
    'host': getEdiHost(), 
    'path': buildPathFromObject(options.path, options.urlParams), 
    'method': options.method || 'GET', 
    'headers': composedHeaders, 
    'rejectUnauthorized': false 
    }); 

    let header = Buffer.from(`--${boundaryUuid} 
    Content-Disposition: form-data; name="route" 

    ${JSON.stringify(data[0])}) 
    --${boundaryUuid} 
    Content-Disposition: form-data; name="files"; filename="${file.name}" 
    Content-Type: ${file.contentType} 

    `.replace(/\r?\n */gm, '\r\n')) 
    let footer = Buffer.from(`\r\n--${boundaryUuid}--`) 
    let length = header.length + xlsx.length + footer.length 
    let body = Buffer.concat([header, xlsx, footer], length) 

    composedOptions.headers['Content-Length'] = length; 
    composedOptions.headers['Content-Type'] = `multipart/form-data; boundary=${boundaryUuid}`; 

    let request = https.request(composedOptions); 

    // handle response 
    request.on('response', (httpRequestResponse) => { 
    let chunks = [] 
     , errObject = handleHttpStatusCodes(httpRequestResponse); 
    ; 

    if (errObject !== null) { 
     return cb(errObject, null); 
    } 

    httpRequestResponse.on('data', (chunk) => { chunks.push(chunk); }); 
    httpRequestResponse.on('end',() => { 
     let responseString = Buffer.concat(chunks).toString() 
     ; 

     return cb(null, JSON.parse(responseString)); 
    }); 

    }); 

    request.on('error', (err) => cb(err)); 

    // write multipart to request 
    request.end(body); 
}; 
+0

私の男!それがそれでした。ありがとう! –

0

request.end()はどこにも電話していませんか?

本文を含むリクエストを送信するための(非常に一般的な)フォームはhttps.request(opts).end(body)です。

また、1つの巨大なバッファに蓄積する代わりに、データを送信したい場合は、request.write(buf)と呼ぶことができます(編集:nextTickで行う必要はありません)(EDIT: )であるように、おそらく維持、Content-Lengthを設定しなくなります

+0

リクエストを追加しましたbufを書いた後で.end()を実行します。以前はそのコードを一度に1つずつ記述していましたが、リクエストを送信する前にコンテンツの長さを試してみるように変更しましたが、それは問題だと思っていましたが、そうではないようです。 request.end()を追加した後も同じエラーです。上記のコード例を変更します。しかし、ありがとう.. –

関連する問題