无法读取上传到 AWS S3 的图像
Can' read images uploaded to AWS S3
我正在将图像作为缓冲区上传到 AWS S3
(这是 aws-sdk
的要求),但此图像无法作为普通图像读取 - 它在浏览器中显示就像一个白色的小方块。我在这里缺少什么?
在 Next.js API
const s3 = new AWS.S3({
accessKeyId: "key",
secretAccessKey: "key",
});
const params = {
Bucket: "bucket",
Key: `${Date.now().toString()}.jpg`,
Body: Buffer.from(req.body),
ContentType: "image/png",
};
s3.upload(params, (err, data) => {
if (err) {
throw err;
}
console.log(`File uploaded successfully. ${data}`);
});
客户端:
const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const { files } = e.target;
const formData = new FormData();
if (files && files[0]) {
formData.append("image", files[0]);
fetch("/api/upload.image", {
method: "POST",
body: formData,
});
}
};
这是来自服务器的回答示例:
<ref *2> ManagedUpload {
_events: {},
body: <Buffer 2d 2d 2d 2d 2d 2d 57 65 62 4b 69 74 46 6f 72 6d 42 6f 75 6e 64 61 72 79 51 41 62 63 59 76 32 45 4e 6c 34 77 77 79 70 57 0d 0a 43 6f 6e 74 65 6e 74 2d ... 93798 more bytes>,
sliceFn: [Function: slice],
callback: [Function (anonymous)],
parts: {},
completeInfo: [],
fillQueue: [Function: fillBuffer],
partSize: 5242880,
service: Service {
config: Config {
credentials: [Credentials],
credentialProvider: [CredentialProviderChain],
region: 'us-east-1',
logger: null,
apiVersions: {},
apiVersion: null,
endpoint: 's3.amazonaws.com',
httpOptions: [Object],
maxRetries: undefined,
maxRedirects: 10,
paramValidation: true,
sslEnabled: true,
s3ForcePathStyle: false,
s3BucketEndpoint: false,
s3DisableBodySigning: true,
s3UsEast1RegionalEndpoint: undefined,
s3UseArnRegion: undefined,
computeChecksums: true,
convertResponseTypes: true,
correctClockSkew: false,
customUserAgent: null,
dynamoDbCrc32: true,
systemClockOffset: 0,
signatureVersion: 'v4',
signatureCache: true,
retryDelayOptions: {},
useAccelerateEndpoint: false,
clientSideMonitoring: false,
endpointDiscoveryEnabled: undefined,
endpointCacheSize: 1000,
hostPrefixEnabled: true,
stsRegionalEndpoints: 'legacy',
accessKeyId: 'xxx',
secretAccessKey: 'xxx',
params: [Object]
},
isGlobalEndpoint: false,
endpoint: Endpoint {
protocol: 'https:',
host: 's3.amazonaws.com',
port: 443,
hostname: 's3.amazonaws.com',
pathname: '/',
path: '/',
href: 'https://s3.amazonaws.com/'
},
_events: { apiCallAttempt: [Array], apiCall: [Array] },
MONITOR_EVENTS_BUBBLE: [Function: EVENTS_BUBBLE],
CALL_EVENTS_BUBBLE: [Function: CALL_EVENTS_BUBBLE],
_clientId: 2
},
totalBytes: 93848,
failed: false,
partPos: 5242880,
isDoneChunking: true,
numParts: 1,
totalPartNumbers: 1,
singlePart: <ref *1> Request {
domain: null,
service: Service {
config: [Config],
isGlobalEndpoint: false,
endpoint: [Endpoint],
_events: [Object],
MONITOR_EVENTS_BUBBLE: [Function: EVENTS_BUBBLE],
CALL_EVENTS_BUBBLE: [Function: CALL_EVENTS_BUBBLE],
_clientId: 2
},
operation: 'putObject',
params: {
Body: <Buffer 2d 2d 2d 2d 2d 2d 57 65 62 4b 69 74 46 6f 72 6d 42 6f 75 6e 64 61 72 79 51 41 62 63 59 76 32 45 4e 6c 34 77 77 79 70 57 0d 0a 43 6f 6e 74 65 6e 74 2d ... 93798 more bytes>,
Bucket: 'codest-images',
Key: '1613572736403.jpg',
ContentType: 'image/png',
ACL: 'public-read'
},
httpRequest: HttpRequest {
method: 'PUT',
path: '/1613572736403.jpg',
headers: [Object],
body: <Buffer 2d 2d 2d 2d 2d 2d 57 65 62 4b 69 74 46 6f 72 6d 42 6f 75 6e 64 61 72 79 51 41 62 63 59 76 32 45 4e 6c 34 77 77 79 70 57 0d 0a 43 6f 6e 74 65 6e 74 2d ... 93798 more bytes>,
endpoint: [Object],
region: 'us-east-1',
_userAgent: 'aws-sdk-nodejs/2.840.0 darwin/v14.15.4 callback',
virtualHostedBucket: 'codest-images',
stream: [ClientRequest]
},
startTime: 2021-02-17T14:38:56.406Z,
response: Response {
request: [Circular *1],
data: null,
error: null,
retryCount: 0,
redirectCount: 0,
httpResponse: [HttpResponse],
maxRetries: 3,
maxRedirects: 10
},
_asm: AcceptorStateMachine { currentState: 'send', states: [Object] },
_haltHandlersOnError: false,
_events: {
validate: [Array],
afterBuild: [Array],
restart: [Array],
sign: [Array],
validateResponse: [Array],
send: [Array],
httpHeaders: [Array],
httpData: [Array],
httpDone: [Array],
retry: [Array],
afterRetry: [Array],
build: [Array],
extractData: [Array],
extractError: [Array],
httpError: [Array],
beforePresign: [Array],
success: [Array],
complete: [Array],
httpUploadProgress: [Array]
},
emit: [Function: emit],
API_CALL_ATTEMPT: [Function: API_CALL_ATTEMPT],
API_CALL_ATTEMPT_RETRY: [Function: API_CALL_ATTEMPT_RETRY],
API_CALL: [Function: API_CALL],
_managedUpload: [Circular *2],
signedAt: 2021-02-17T14:38:56.415Z
}
}
您正试图从 req.body
获取图像内容,但这是不正确的。如果你在控制台上打印 req.body
,你会看到这样的东西 -
------WebKitFormBoundary
Content-Disposition: form-data; name="image";
filename="image.jpeg"
Content-Type: application/json
your file content buffer
您可以解析它以获取缓冲区内容。或者我更喜欢使用像 multer
这样的库来从 FormData 读取文件。以下是使用 multer 的 NextJS 代码。
const AWS = require("aws-sdk");
const s3 = new AWS.S3();
var multer = require("multer");
var upload = multer();
export const config = {
api: {
bodyParser: false, // This is important. Else multer won't be parsing your form data
},
};
export default async function handler(req, res) {
upload.single("image")(req, {}, (err) => { // 'image' is the element name in the form
console.log(req.file); // you will see file metadata and the buffer here
const params = {
Bucket: "bucket",
Key: `${Date.now().toString()}.jpg`,
Body: req.file.buffer,
ContentType: "image/jpeg",
};
s3.upload(params, (err, data) => {
if (err) {
res.status(500).send({ message: "Error while uploading" });
} else {
console.log(`File uploaded successfully`, data);
res.status(200).send({ message: "File uploaded succesfully" });
}
});
});
}
最后就这样解决了
import { NextApiRequest, NextApiResponse } from "next";
import AWS from "aws-sdk";
import fs from "fs";
import formidable, { File as FFile } from "formidable";
export const config = {
api: {
bodyParser: false,
},
};
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
): Promise<void> {
try {
const s3 = new AWS.S3({
accessKeyId: "xxx",
secretAccessKey: "xxx",
});
const form = new formidable.IncomingForm();
form.uploadDir = "./";
form.keepExtensions = true;
form.parse(req, (err, fields, files) => {
fs.readFile((files.image as FFile).path, (_, image) => {
const params = {
Bucket: "codest-images",
Key: (files.image as FFile).name,
Body: image,
ContentType: (files.image as FFile).type,
ContentSize: (files.image as FFile).size,
ACL: "public-read",
};
s3.upload(
params,
(error: Error, data: AWS.S3.ManagedUpload.SendData) => {
if (error) {
res.status(400).json(error.message);
res.end();
} else {
res.status(200).json(data.Location);
}
}
);
});
});
} catch (ex) {
res.status(400).json({ err: ex });
res.end();
}
}
我正在将图像作为缓冲区上传到 AWS S3
(这是 aws-sdk
的要求),但此图像无法作为普通图像读取 - 它在浏览器中显示就像一个白色的小方块。我在这里缺少什么?
在 Next.js API
const s3 = new AWS.S3({
accessKeyId: "key",
secretAccessKey: "key",
});
const params = {
Bucket: "bucket",
Key: `${Date.now().toString()}.jpg`,
Body: Buffer.from(req.body),
ContentType: "image/png",
};
s3.upload(params, (err, data) => {
if (err) {
throw err;
}
console.log(`File uploaded successfully. ${data}`);
});
客户端:
const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const { files } = e.target;
const formData = new FormData();
if (files && files[0]) {
formData.append("image", files[0]);
fetch("/api/upload.image", {
method: "POST",
body: formData,
});
}
};
这是来自服务器的回答示例:
<ref *2> ManagedUpload {
_events: {},
body: <Buffer 2d 2d 2d 2d 2d 2d 57 65 62 4b 69 74 46 6f 72 6d 42 6f 75 6e 64 61 72 79 51 41 62 63 59 76 32 45 4e 6c 34 77 77 79 70 57 0d 0a 43 6f 6e 74 65 6e 74 2d ... 93798 more bytes>,
sliceFn: [Function: slice],
callback: [Function (anonymous)],
parts: {},
completeInfo: [],
fillQueue: [Function: fillBuffer],
partSize: 5242880,
service: Service {
config: Config {
credentials: [Credentials],
credentialProvider: [CredentialProviderChain],
region: 'us-east-1',
logger: null,
apiVersions: {},
apiVersion: null,
endpoint: 's3.amazonaws.com',
httpOptions: [Object],
maxRetries: undefined,
maxRedirects: 10,
paramValidation: true,
sslEnabled: true,
s3ForcePathStyle: false,
s3BucketEndpoint: false,
s3DisableBodySigning: true,
s3UsEast1RegionalEndpoint: undefined,
s3UseArnRegion: undefined,
computeChecksums: true,
convertResponseTypes: true,
correctClockSkew: false,
customUserAgent: null,
dynamoDbCrc32: true,
systemClockOffset: 0,
signatureVersion: 'v4',
signatureCache: true,
retryDelayOptions: {},
useAccelerateEndpoint: false,
clientSideMonitoring: false,
endpointDiscoveryEnabled: undefined,
endpointCacheSize: 1000,
hostPrefixEnabled: true,
stsRegionalEndpoints: 'legacy',
accessKeyId: 'xxx',
secretAccessKey: 'xxx',
params: [Object]
},
isGlobalEndpoint: false,
endpoint: Endpoint {
protocol: 'https:',
host: 's3.amazonaws.com',
port: 443,
hostname: 's3.amazonaws.com',
pathname: '/',
path: '/',
href: 'https://s3.amazonaws.com/'
},
_events: { apiCallAttempt: [Array], apiCall: [Array] },
MONITOR_EVENTS_BUBBLE: [Function: EVENTS_BUBBLE],
CALL_EVENTS_BUBBLE: [Function: CALL_EVENTS_BUBBLE],
_clientId: 2
},
totalBytes: 93848,
failed: false,
partPos: 5242880,
isDoneChunking: true,
numParts: 1,
totalPartNumbers: 1,
singlePart: <ref *1> Request {
domain: null,
service: Service {
config: [Config],
isGlobalEndpoint: false,
endpoint: [Endpoint],
_events: [Object],
MONITOR_EVENTS_BUBBLE: [Function: EVENTS_BUBBLE],
CALL_EVENTS_BUBBLE: [Function: CALL_EVENTS_BUBBLE],
_clientId: 2
},
operation: 'putObject',
params: {
Body: <Buffer 2d 2d 2d 2d 2d 2d 57 65 62 4b 69 74 46 6f 72 6d 42 6f 75 6e 64 61 72 79 51 41 62 63 59 76 32 45 4e 6c 34 77 77 79 70 57 0d 0a 43 6f 6e 74 65 6e 74 2d ... 93798 more bytes>,
Bucket: 'codest-images',
Key: '1613572736403.jpg',
ContentType: 'image/png',
ACL: 'public-read'
},
httpRequest: HttpRequest {
method: 'PUT',
path: '/1613572736403.jpg',
headers: [Object],
body: <Buffer 2d 2d 2d 2d 2d 2d 57 65 62 4b 69 74 46 6f 72 6d 42 6f 75 6e 64 61 72 79 51 41 62 63 59 76 32 45 4e 6c 34 77 77 79 70 57 0d 0a 43 6f 6e 74 65 6e 74 2d ... 93798 more bytes>,
endpoint: [Object],
region: 'us-east-1',
_userAgent: 'aws-sdk-nodejs/2.840.0 darwin/v14.15.4 callback',
virtualHostedBucket: 'codest-images',
stream: [ClientRequest]
},
startTime: 2021-02-17T14:38:56.406Z,
response: Response {
request: [Circular *1],
data: null,
error: null,
retryCount: 0,
redirectCount: 0,
httpResponse: [HttpResponse],
maxRetries: 3,
maxRedirects: 10
},
_asm: AcceptorStateMachine { currentState: 'send', states: [Object] },
_haltHandlersOnError: false,
_events: {
validate: [Array],
afterBuild: [Array],
restart: [Array],
sign: [Array],
validateResponse: [Array],
send: [Array],
httpHeaders: [Array],
httpData: [Array],
httpDone: [Array],
retry: [Array],
afterRetry: [Array],
build: [Array],
extractData: [Array],
extractError: [Array],
httpError: [Array],
beforePresign: [Array],
success: [Array],
complete: [Array],
httpUploadProgress: [Array]
},
emit: [Function: emit],
API_CALL_ATTEMPT: [Function: API_CALL_ATTEMPT],
API_CALL_ATTEMPT_RETRY: [Function: API_CALL_ATTEMPT_RETRY],
API_CALL: [Function: API_CALL],
_managedUpload: [Circular *2],
signedAt: 2021-02-17T14:38:56.415Z
}
}
您正试图从 req.body
获取图像内容,但这是不正确的。如果你在控制台上打印 req.body
,你会看到这样的东西 -
------WebKitFormBoundary
Content-Disposition: form-data; name="image";
filename="image.jpeg"
Content-Type: application/json
your file content buffer
您可以解析它以获取缓冲区内容。或者我更喜欢使用像 multer
这样的库来从 FormData 读取文件。以下是使用 multer 的 NextJS 代码。
const AWS = require("aws-sdk");
const s3 = new AWS.S3();
var multer = require("multer");
var upload = multer();
export const config = {
api: {
bodyParser: false, // This is important. Else multer won't be parsing your form data
},
};
export default async function handler(req, res) {
upload.single("image")(req, {}, (err) => { // 'image' is the element name in the form
console.log(req.file); // you will see file metadata and the buffer here
const params = {
Bucket: "bucket",
Key: `${Date.now().toString()}.jpg`,
Body: req.file.buffer,
ContentType: "image/jpeg",
};
s3.upload(params, (err, data) => {
if (err) {
res.status(500).send({ message: "Error while uploading" });
} else {
console.log(`File uploaded successfully`, data);
res.status(200).send({ message: "File uploaded succesfully" });
}
});
});
}
最后就这样解决了
import { NextApiRequest, NextApiResponse } from "next";
import AWS from "aws-sdk";
import fs from "fs";
import formidable, { File as FFile } from "formidable";
export const config = {
api: {
bodyParser: false,
},
};
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
): Promise<void> {
try {
const s3 = new AWS.S3({
accessKeyId: "xxx",
secretAccessKey: "xxx",
});
const form = new formidable.IncomingForm();
form.uploadDir = "./";
form.keepExtensions = true;
form.parse(req, (err, fields, files) => {
fs.readFile((files.image as FFile).path, (_, image) => {
const params = {
Bucket: "codest-images",
Key: (files.image as FFile).name,
Body: image,
ContentType: (files.image as FFile).type,
ContentSize: (files.image as FFile).size,
ACL: "public-read",
};
s3.upload(
params,
(error: Error, data: AWS.S3.ManagedUpload.SendData) => {
if (error) {
res.status(400).json(error.message);
res.end();
} else {
res.status(200).json(data.Location);
}
}
);
});
});
} catch (ex) {
res.status(400).json({ err: ex });
res.end();
}
}