Node.js AWS S3-无法显示图像,因为它包含错误
我目前正在用React、Redux、JavaScript、Node和Adonisjs构建一个注册表单。我正在尝试将配置文件图像上载到我的AWS s3存储桶。目前,我已经得到了它,所以文件出现在桶中。但是,当我尝试单击AWS s3提供的链接时,我得到以下错误 我已将权限设置为public,并提供了正确的凭据密钥。我被困在如何解决这个问题,所以任何帮助都将不胜感激。请参阅下面的代码 下面是我的AWS控制器:Node.js AWS S3-无法显示图像,因为它包含错误,node.js,reactjs,amazon-web-services,amazon-s3,image-uploading,Node.js,Reactjs,Amazon Web Services,Amazon S3,Image Uploading,我目前正在用React、Redux、JavaScript、Node和Adonisjs构建一个注册表单。我正在尝试将配置文件图像上载到我的AWS s3存储桶。目前,我已经得到了它,所以文件出现在桶中。但是,当我尝试单击AWS s3提供的链接时,我得到以下错误 我已将权限设置为public,并提供了正确的凭据密钥。我被困在如何解决这个问题,所以任何帮助都将不胜感激。请参阅下面的代码 下面是我的AWS控制器: "use strict"; require("dotenv").config(); con
"use strict";
require("dotenv").config();
const aws = require("aws-sdk");
const fs = require("fs");
const Helpers = use("Helpers");
const Drive = use("Drive");
class awsController {
async upload({ request, response }) {
aws.config.update({
region: "ap-southeast-2", // AWS region
accessKeyId: process.env.S3_KEY,
secretAccessKey: process.env.S3_SECERT
});
const S3_BUCKET = process.env.S3_BUCKET;
const s3Bucket = new aws.S3({
region: "ap-southeast-2",
accessKeyId: process.env.S3_KEY,
secretAccessKey: process.env.S3_SECERT,
Bucket: process.env.S3_BUCKET
}); // Create a new instance of S3
const fileName = request.all().body.fileName;
console.log(fileName);
const fileType = request.all().body.fileType;
const params = {
Bucket: S3_BUCKET,
Key: fileName,
ContentType: fileType,
ACL: "public-read"
};
s3Bucket.putObject(params, function(err, data) {
if (err) {
response.send(err);
}
console.log(data);
const returnData = {
signedRequest: data,
url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}`
};
console.log(returnData);
response.send("Success");
});
}
}
module.exports = awsController;
**下面处理文件的上载**
import React, { Component } from "react";
import axiosAPI from "./../resorterAPI";
import axios from "axios";
class ImageUpload extends Component {
constructor(props) {
super(props);
this.state = {
success: false,
url: ""
};
}
handleChange = event => {};
handleUpload = event => {
let uploadedFile = this.uploadInput.files[0];
// Splits name of file
let fileParts = this.uploadInput.files[0].name.split(".");
let fileName = fileParts[0];
let fileType = fileParts[1];
let fullFileName = uploadedFile.name;
console.log("preparing upload");
axiosAPI
.post("/s3Upload", {
body: {
fileName:
Math.round(Math.random() * 1000 * 300000).toString() +
"_" +
uploadedFile.name,
fileType: fileType
}
})
.then(response => {
console.log("Success");
});
};
render() {
return (
<div>
<center>
<input
onChange={this.handleChange}
ref={ref => {
this.uploadInput = ref;
}}
type="file"
/>
<br />
<button onClick={this.handleUpload}> Upload </button>
</center>
</div>
);
}
}
export default ImageUpload;
从“React”导入React,{Component};
从“/。/resorterAPI”导入axiosAPI;
从“axios”导入axios;
类ImageUpload扩展组件{
建造师(道具){
超级(道具);
此.state={
成功:错,
网址:“
};
}
handleChange=event=>{};
handleUpload=事件=>{
让uploadedFile=this.uploadInput.files[0];
//拆分文件名
让fileParts=this.uploadInput.files[0].name.split(“.”);
让fileName=fileParts[0];
让fileType=fileParts[1];
让fullFileName=uploadedFile.name;
控制台日志(“准备上传”);
axiosAPI
.post(“/s3Upload”{
正文:{
文件名:
Math.round(Math.random()*1000*300000).toString()+
"_" +
uploadedFile.name,
fileType:fileType
}
})
。然后(响应=>{
控制台日志(“成功”);
});
};
render(){
返回(
{
this.uploadInput=ref;
}}
type=“文件”
/>
上传
);
}
}
导出默认图像上传;
**下面是调用图像上传服务的地方**
import React from "react";
// Redux
import { Field, reduxForm } from "redux-form";
import { connect } from "react-redux";
import { getCountry } from "./../../redux/actions/getCountryAction.js";
import Store from "./../../redux/store.js";
// Services
import axiosAPI from "./../../api/resorterAPI";
import ImageUpload from "./../../api/services/ImageUpload";
// Calls a js file with all area codes matched to countries.
import phoneCodes from "./../../materials/PhoneCodes.json";
// Component Input
import {
renderField,
renderSelectField,
renderFileUploadField
} from "./../FormField/FormField.js";
// CSS
import styles from "./signupForm.module.css";
import classNames from "classnames";
function validate(values) {
let errors = {};
if (!values.specialisations) {
errors.firstName = "Required";
}
if (!values.resort) {
errors.lastName = "Required";
}
if (!values.yearsOfExperience) {
errors.email = "Required";
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = "Invalid Email";
}
if (!values.spokenLanguages) {
errors.password = "Required";
}
if (values.sport !== values.confirmPassword) {
errors.confirmPassword = "Passwords don't match";
}
return errors;
}
class SignupFormStepTwo extends React.Component {
constructor(props) {
super(props);
this.state = {
countries: [],
selectedCountry: [],
dialCodes: []
};
}
// Below gets the countries from axios call made in redux actions
async componentDidMount() {
const countries = await getCountry();
// The below maps through the json file and gets all the dial codes
const codes = phoneCodes.phoneCode.map(code => {
return code.dial_code;
});
return this.setState({ countries: countries, dialCodes: codes });
}
// Handles when someone changes the select fields
handleChange = event => {
const selectedCountry = event.target.value;
return this.setState({ selectedCountry: selectedCountry });
};
// uploadFile = (values, url = "") => {
// axiosAPI.post("/displayImageUpload", { ...values, imageURL: url}).then(response => {
// console.log("Success");
// })
// }
render() {
return (
<div>
<form onSubmit={this.props.handleSubmit}>
<div className={styles.signupContainer}>
<div className={styles.signupInputContainer}>
{/* <Field
name="displayImage"
component={renderFileUploadField}
type="text"
label="Display Image"
/> */}
<ImageUpload />
<div
className={classNames({
[styles.bioField]: true,
[styles.signupInputContainer]: true
})}
>
<Field
name="bio"
component={renderField}
type="text"
label="Bio"
placeholder="Introduce yourself - Where you're from, what your hobbies are, etc..."
/>
</div>
</div>
{/* Renders the select field */}
<div className={styles.signupInputContainer}>
<Field
name="specialisations"
component={renderSelectField}
type="select"
label="Specialisations"
placeholder="Specialisations"
options={this.state.countries}
onChange={this.handleChange}
multiple={false}
/>
<Field
name="resort"
component={renderSelectField}
options={this.state.dialCodes}
type="select"
label="Resort"
placeholder="Select the resorts you can work at"
/>
<Field
name="yearsOfExperience"
component={renderSelectField}
options={this.state.dialCodes}
type="select"
label="Years of Experience"
/>
<Field
name="spokenLanguages"
component={renderSelectField}
options={this.state.dialCodes}
type="select"
label="Spoken Languages"
/>
</div>
</div>
<div className={styles.signupButtonContainer}>
<button className={styles.signupButton} type="submit">
{" "}
Submit{" "}
</button>
</div>
</form>
</div>
);
}
}
// destroyOnUnmount - saves it in state
SignupFormStepTwo = reduxForm({
form: "signupStageTwo",
destroyOnUnmount: false,
validate
})(SignupFormStepTwo);
const mapStateToProps = state => {
return {
form: state.form
};
};
export default SignupFormStepTwo;
从“React”导入React;
//重演
从“redux表单”导入{Field,reduxForm};
从“react redux”导入{connect};
从“/./../redux/actions/getCountryAction.js”导入{getCountry}”;
从“/./../redux/Store.js”导入存储;
//服务
从“/./../api/resorterAPI”导入axiosAPI;
从“/./../api/services/ImageUpload”导入ImageUpload;
//调用包含与国家/地区匹配的所有区号的js文件。
从“/./../materials/phoneCodes.json”导入电话码;
//组件输入
进口{
伦德菲尔德,
renderSelectField,
renderFileUploadField
}来自“/。/FormField/FormField.js”;
//CSS
从“/signupForm.module.css”导入样式;
从“类名”中导入类名;
函数验证(值){
让错误={};
if(!values.specializations){
errors.firstName=“必需”;
}
如果(!values.resort){
errors.lastName=“必需”;
}
如果(!values.yearsof experience){
errors.email=“必需”;
}如果(!/^[A-Z0-9.%+-]+@[A-Z0-9.-]+\[A-Z]{2,4}$/i.test(values.email)){
errors.email=“无效电子邮件”;
}
如果(!values.spokenLanguages){
errors.password=“必需”;
}
if(values.sport!==values.confirmPassword){
errors.confirmPassword=“密码不匹配”;
}
返回错误;
}
类SignupFormStep2扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
国家:[],
所选国家:[],
拨号代码:[]
};
}
//下面是redux操作中axios调用的国家/地区
异步组件didmount(){
const countries=等待getCountry();
//下面的代码映射到json文件并获取所有拨号代码
const code=phoneCode.phoneCode.map(代码=>{
返回代码。拨号代码;
});
返回此.setState({countries:countries,dialCodes:codes});
}
//当有人更改“选择”字段时处理
handleChange=事件=>{
const selectedCountry=event.target.value;
返回此.setState({selectedCountry:selectedCountry});
};
//uploadFile=(值,url=”“)=>{
//post(“/displayImageUpload”,{…值,imageURL:url})。然后(响应=>{
//控制台日志(“成功”);
// })
// }
render(){
返回(
{/* */}
{/*呈现选择字段*/}
{" "}
提交{“}
);
}
}
//destroyOnUnmount-将其保存为状态
SignupFormStep2=reduxForm({
表格:“signupstagewo”,
DestroyOnMont:false,
验证
})(第二步注册);
常量mapStateToProps=状态=>{
返回{
表单:state.form
};
};
导出默认注册表单第二步;
更新:由于Jarmod解决了错误,我实际上没有将文件扩展名与文件名分离,因此它上载image.png.png。图像类型是否与文件扩展名和/或内容类型不匹配?你能下载文件并验证它的内容实际上是JPEG吗?嘿@Jarmod,我正在将内容类型设置为当前上传的图像的任何类型。那么,这不应该总是确保它匹配吗?如您所见,我正在通过ContentType传递fileType。这回答了你的问题吗?@jarmod-你是对的,它上载的文件名带有扩展名,所以它上载的是image.png.png。我已经解决了这个错误,但是现在文件没有内容,所以它出现在bucket中,但它是一个空文本文档。我将为此问题创建一个新帖子。谢谢您的帮助。您的putObject
呼叫没有正文。