我正在尝试重新创建一段代码,以将大文件上传到S3。我转载了this repo。
很不幸,当尝试上传一个很小的文件时,我收到一个MalformedXML
错误。有人看到我所缺少的吗?
这是后端代码:
const express = require('express')
const app = express()
const BluebirdPromise = require('bluebird')
const AWS = require('aws-sdk')
const bodyParser = require('body-parser')
app.use(bodyParser.json())
const port = 4000
const BUCKET_NAME = "mybucket"
const s3 = new AWS.S3({
accessKeyId: 'ACCESS_KEY_ID' , // Replace with your access key id
secretAccessKey: 'SECRET_ACCESS_KEY' , // Replace with your secret access key
s3ForcePathStyle: true,
signatureVersion: 'v4'
});
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.get('/start-upload', async (req, res, next) => {
try {
let params = {
Bucket: BUCKET_NAME,
Key: req.query.fileName,
ContentType: req.query.fileType
}
let createUploadPromised = BluebirdPromise.promisify(s3.createMultipartUpload.bind(s3))
let uploadData = await createUploadPromised(params)
res.send({uploadId: uploadData.UploadId})
} catch(err) {
console.log(err)
}
})
app.get('/get-upload-url', async (req, res, next) => {
try {
let params = {
Bucket: BUCKET_NAME,
Key: req.query.fileName,
PartNumber: req.query.partNumber,
UploadId: req.query.uploadId
}
console.log(params)
let uploadPartPromised = BluebirdPromise.promisify(s3.getSignedUrl.bind(s3))
let presignedUrl = await uploadPartPromised('uploadPart', params)
res.send({presignedUrl})
} catch(err) {
console.log(err)
}
})
app.post('/complete-upload', async (req, res, next) => {
try {
console.log(req.body, ': body')
let params = {
Bucket: BUCKET_NAME,
Key: req.body.params.fileName,
MultipartUpload: {
Parts: req.body.params.parts
},
UploadId: req.body.params.uploadId
}
console.log(params)
let completeUploadPromised = BluebirdPromise.promisify(s3.completeMultipartUpload.bind(s3))
let data = await completeUploadPromised(params)
res.send({data})
} catch(err) {
console.log(err)
}
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
这是前端代码:
import React, { Component } from 'react'
import axios from 'axios'
export default class Index extends Component {
constructor(props) {
super(props)
this.state = {
selectedFile: null,
uploadId: '',
fileName: '',
backendUrl: 'http://localhost:4000'
}
}
async fileChangedHandler(event) {
try {
// console.log('Inside fileChangedHandler')
let selectedFile = event.target.files[0]
let fileName = selectedFile.name
this.setState({ selectedFile })
this.setState({ fileName })
} catch (err) {
console.error(err, err.message)
}
}
async startUpload(event) {
try {
// console.log('Inside startUpload')
event.preventDefault()
console.log(this.state.selectedFile.type + ' FileType')
let resp = await axios.get(`${this.state.backendUrl}/start-upload`, {
params: {
fileName: this.state.fileName,
fileType: this.state.selectedFile.type
}
})
let {uploadId} = resp.data
this.setState({uploadId})
this.uploadMultipartFile()
} catch(err) {
console.log(err)
}
}
async uploadMultipartFile() {
try {
console.log('Inside uploadMultipartFile')
const FILE_CHUNK_SIZE = 10000000 // 10MB
const fileSize = this.state.selectedFile.size
const NUM_CHUNKS = Math.floor(fileSize / FILE_CHUNK_SIZE) + 1
let promisesArray = []
let start, end, blob
for (let index = 1; index < NUM_CHUNKS + 1; index++) {
start = (index - 1)*FILE_CHUNK_SIZE
end = (index)*FILE_CHUNK_SIZE
blob = (index < NUM_CHUNKS) ? this.state.selectedFile.slice(start, end) : this.state.selectedFile.slice(start)
// (1) Generate presigned URL for each part
let getUploadUrlResp = await axios.get(`${this.state.backendUrl}/get-upload-url`, {
params: {
fileName: this.state.fileName,
partNumber: index,
uploadId: this.state.uploadId
}
})
let { presignedUrl } = getUploadUrlResp.data
console.log(' Presigned URL ' + index + ': ' + presignedUrl + ' filetype ' + this.state.selectedFile.type)
// (2) Puts each file part into the storage server
let uploadResp = axios.put(
presignedUrl,
blob,
{ headers: { 'Content-Type': this.state.selectedFile.type } }
)
// console.log(' Upload no ' + index + '; Etag: ' + uploadResp.headers.etag)
promisesArray.push(uploadResp)
}
let resolvedArray = await Promise.all(promisesArray)
console.log(resolvedArray, ' resolvedAr')
let uploadPartsArray = []
resolvedArray.forEach((resolvedPromise, index) => {
uploadPartsArray.push({
ETag: resolvedPromise.headers.etag,
PartNumber: index + 1
})
})
// (3) Calls the CompleteMultipartUpload endpoint in the backend server
let completeUploadResp = await axios.post(`${this.state.backendUrl}/complete-upload`, {
params: {
fileName: this.state.fileName,
parts: uploadPartsArray,
uploadId: this.state.uploadId
}
})
console.log(completeUploadResp.data, ' Stuff')
} catch(err) {
console.log(err)
}
}
render() {
return (
<div>
<form onSubmit={this.startUpload.bind(this)}>
<div>
<p>Upload Dataset:</p>
<input type='file' id='file' onChange={this.fileChangedHandler.bind(this)} />
<button type='submit'>
Upload
</button>
</div>
</form>
</div>
)
}
}
以下是输出:
Example app listening on port 4000!
{
Bucket: 'mybucket',
Key: 'myobject.jpg',
PartNumber: '1',
UploadId: 'wCFRpYX96oG4sQaAAKVmP_4.r0Z5cxWsTUD9U.UDuHxNhQImMIMwUNEeJY_VNrfn5e5YflO4j9Uyo9wb611bwXbu_HQg9TpvJCmFIPZqAE6V_dJFfzsmKYCba5KsFALw'
}
{
params: {
fileName: 'myobject.jpg',
parts: [ [Object] ],
uploadId: 'wCFRpYX96oG4sQaAAKVmP_4.r0Z5cxWsTUD9U.UDuHxNhQImMIMwUNEeJY_VNrfn5e5YflO4j9Uyo9wb611bwXbu_HQg9TpvJCmFIPZqAE6V_dJFfzsmKYCba5KsFALw'
}
} : body
{
Bucket: 'mybucket',
Key: 'myobject.jpg',
MultipartUpload: { Parts: [ [Object] ] },
UploadId: 'wCFRpYX96oG4sQaAAKVmP_4.r0Z5cxWsTUD9U.UDuHxNhQImMIMwUNEeJY_VNrfn5e5YflO4j9Uyo9wb611bwXbu_HQg9TpvJCmFIPZqAE6V_dJFfzsmKYCba5KsFALw'
}
MalformedXML: The XML you provided was not well-formed or did not validate against our published schema
at Request.extractError (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/services/s3.js:583:35)
at Request.callListeners (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
at Request.emit (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
at Request.emit (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:683:14)
at Request.transition (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:685:12)
at Request.callListeners (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/sequential_executor.js:116:18)
at Request.emit (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
at Request.emit (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:683:14)
at Request.transition (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:38:9) {
cause: MalformedXML: The XML you provided was not well-formed or did not validate against our published schema
at Request.extractError (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/services/s3.js:583:35)
at Request.callListeners (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
at Request.emit (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
at Request.emit (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:683:14)
at Request.transition (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:685:12)
at Request.callListeners (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/sequential_executor.js:116:18)
at Request.emit (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
at Request.emit (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:683:14)
at Request.transition (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/home/aws-s3-multipart-presigned-upload/backend/node_modules/aws-sdk/lib/request.js:38:9) {
message: 'The XML you provided was not well-formed or did not validate against our published schema',
code: 'MalformedXML',
region: null,
time: 2019-10-17T13:32:46.655Z,
requestId: 'E275D080E8B60488',
extendedRequestId: '5zOuxT+sl/BOOOn+pmgHjOO4jUI3YtrYC4KeXJKwwl9ID2mCzb997cF66hI1A03ZjHCQq0dhDx4=',
cfId: undefined,
statusCode: 400,
retryable: false,
retryDelay: 58.95911735466519
},
isOperational: true,
code: 'MalformedXML',
region: null,
time: 2019-10-17T13:32:46.655Z,
requestId: 'E275D080E8B60488',
extendedRequestId: '5zOuxT+sl/BOOOn+pmgHjOO4jUI3YtrYC4KeXJKwwl9ID2mCzb997cF66hI1A03ZjHCQq0dhDx4=',
cfId: undefined,
statusCode: 400,
retryable: false,
retryDelay: 58.95911735466519
}
谢谢您的帮助!