douli4337 2019-07-18 01:06
浏览 199
已采纳

如何通过react / axios和golang / gin将图像上传到S3

I want to make functionality to post image to S3 in following steps.

  1. user upload image(s) on the screen.
  2. image files are sent to server after submitting
  3. images are uploaded to S3 in server side(golang).

Now issue is at 3."images are uploaded to S3 in server side(golang)."

There is nil error at server side code.

debug shows nil value at this method.

form, _ := c.MultipartForm()

Here is the codes.

//import

interface ArticleState {
  title: string;
  content: string;
  redirect: boolean;
  files: File[];
}

class Post extends React.Component<{}, ArticleState> {
  constructor(props: {}) {
    super(props);
    this.state = {
      title: '',
      content: '',
      redirect: false,
      files: [],
    };
    this.handleChangeTitle = this.handleChangeTitle.bind(this);
    this.handleChangeContent = this.handleChangeContent.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.renderRedirect = this.renderRedirect.bind(this);
    this.handleOnDrop = this.handleOnDrop.bind(this);
  }

  handleOnDrop(acceptedFiles: File[]) {
    this.setState({files: this.state.files.concat(acceptedFiles)});
  }

  handleChangeTitle(e: React.FormEvent<HTMLInputElement>) {
    this.setState({title: e.currentTarget.value});
  }

  handleChangeContent(e: React.FormEvent<HTMLInputElement>) {
    this.setState({content: e.currentTarget.value});
  }

  handleSubmit() {
    this.setState({
      redirect: true,
    });
    const data = {
      title: this.state.title,
      content: this.state.content,
      files: this.state.files,
    };
    axios.post('http://localhost:4000/api/post', data).then(res => {
      console.log(res);
    });
  }

  renderRedirect = () => {
    if (this.state.redirect) {
      return <Redirect to="/post/finish" />;
    }
  };

  render() {
    return (
      <Container text style={{marginTop: '3em'}}>
        <Form>
          <Form.Input
            label="Title"
            placeholder=""
            name="title"
            value={this.state.title}
            onChange={this.handleChangeTitle}
          />
          <Form.Field
            label="Content"
            placeholder=""
            name="content"
            value={this.state.content}
            rows="20"
            control="textarea"
            onChange={this.handleChangeContent}
          />
          {this.renderRedirect()}
          <input type="file" id="file" hidden /> */}
          <Dropzone accept="image/*" onDrop={this.handleOnDrop}>
            {({getRootProps, getInputProps, open}) => (
              <section>
                <div {...getRootProps()} style={{margin: '20px auto'}}>
                  <input {...getInputProps()} />
                  <p>Drag 'n' drop some files here, or click to select files</p>
                  <button type="button" onClick={open}>
                    Open File Dialog
                  </button>
                </div>
              </section>
            )}
          </Dropzone>
          <Form.Button content="Submit" onClick={this.handleSubmit} />
        </Form>
      </Container>
    );
  }
}

export default Post;
package main

//import

type Article struct {
    ID      int    `json:"id"`
    TITLE   string `json:"title"`
    CONTENT string `json:"content"`
}

var articles []Article

type Param struct {
    Bucket      string
    Key         string
    Expires     string
    ContentType string
}

func main() {

    awsAccessKeyID := "Insert Key Here"
    awsSecretAccessKey := "Insert Secret Here"
    token := ""

    //some codes for mysql connection

    router.Use(
    // some codes
    )

    api := router.Group("/api")
    {
        api.POST("/post", func(c *gin.Context) {
            //some codes for inserting article data in mysql

            creds := credentials.NewStaticCredentials(awsAccessKeyID, awsSecretAccessKey, token)

            cfg := aws.NewConfig().WithRegion("ap-northeast-1").WithCredentials(creds)
            svc := s3.New(session.New(), cfg)

            //Here form value is nill.
            form, _ := c.MultipartForm()
            files := form.File["upload[]"]

            for _, file := range files {
                f, err := file.Open()

                defer f.Close()
                fileInfo, _ := f.(*os.File).Stat()
                size := fileInfo.Size()
                buffer := make([]byte, size)

                f.Read(buffer)
                fileBytes := bytes.NewReader(buffer)
                fileType := http.DetectContentType(buffer)
                path := "/media/" + f.(*os.File).Name()
                params := &s3.PutObjectInput{
                    Bucket:        aws.String("bucketname"),
                    Key:           aws.String(path),
                    Body:          fileBytes,
                    ContentLength: aws.Int64(size),
                    ContentType:   aws.String(fileType),
                }
                resp, err := svc.PutObject(params)
                fmt.Printf("response %s", awsutil.StringValue(resp))
            }

            c.JSON(http.StatusOK, gin.H{"status": "ok"})

        })
    }

    router.Run(":4000")
}

I expected image(s) are uploaded to S3, but actually not uploaded with server error.

The following is error messages.

POST http://localhost:4000/api/post 500 (Internal Server Error)
createError.js:17 Uncaught (in promise) Error: Request failed with status code 500
    at createError (createError.js:17)
    at settle (settle.js:19)
    at XMLHttpRequest.handleLoad (xhr.js:60)
[GIN] 2019/07/18 - 08:47:34 | 204 |      33.322µs |             ::1 | OPTIONS  /api/post

2019/07/18 08:47:34 [Recovery] 2019/07/18 - 08:47:34 panic recovered:
POST /api/post HTTP/1.1
Host: localhost:4000
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 68
Content-Type: application/json;charset=UTF-8
Origin: http://localhost:3000
Referer: http://localhost:3000/post/finish
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36


runtime error: invalid memory address or nil pointer dereference
/usr/local/go/src/runtime/panic.go:82 (0x10426f0)
        panicmem: panic(memoryError)
/usr/local/go/src/runtime/signal_unix.go:390 (0x104251f)
        sigpanic: panicmem()
/Users/jpskgc/go/src/github.com/gin-gonic/gin/context.go:532 (0x17122f5)
        (*Context).MultipartForm: return c.Request.MultipartForm, err
/Users/jpskgc/go/src/github.com/gin-gonic/gin/context.go:147 (0x14fdea9)
        (*Context).Next: c.handlers[c.index](c)
/Users/jpskgc/go/src/github.com/gin-gonic/gin/recovery.go:83 (0x1511939)
        RecoveryWithWriter.func1: c.Next()
/Users/jpskgc/go/src/github.com/gin-gonic/gin/context.go:147 (0x14fdea9)
        (*Context).Next: c.handlers[c.index](c)
/Users/jpskgc/go/src/github.com/gin-gonic/gin/logger.go:240 (0x15109e0)
        LoggerWithConfig.func1: c.Next()
/Users/jpskgc/go/src/github.com/gin-gonic/gin/context.go:147 (0x14fdea9)
        (*Context).Next: c.handlers[c.index](c)
/Users/jpskgc/go/src/github.com/gin-gonic/gin/gin.go:391 (0x1507da9)
        (*Engine).handleHTTPRequest: c.Next()
/Users/jpskgc/go/src/github.com/gin-gonic/gin/gin.go:352 (0x150749d)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2774 (0x12e2207)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1878 (0x12dddf0)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1337 (0x1059ed0)
        goexit: BYTE    $0x90   // NOP

[GIN] 2019/07/18 - 08:47:34 | 500 |  119.560492ms |             ::1 | POST     /api/post
  • frontend: react/axios
  • backend: golang/gin
  • upload library: dropzone
  • storage: amazon s3
  • 写回答

1条回答 默认 最新

  • douyan0732 2019-07-22 02:52
    关注

    I resolved this issue by separating requests. Following is the codes I fixed.

    //React
        const data = {
          title: this.state.title,
          content: this.state.content,
        };
    
        const res = await axios.post('http://localhost:2345/api/post', data);
    
        const formData = new FormData();
        for (var i in this.state.files) {
          formData.append('images[]', this.state.files[i]);
        }
    
        const resImageNames = await axios.post(
          'http://localhost:2345/api/post/image',
          formData,
          {
            headers: {'Content-Type': 'multipart/form-data'},
          }
        );
      }
    
    //Golang
            api.POST("/post", func(c *gin.Context) {
                u, err := uuid.NewRandom()
                if err != nil {
                    fmt.Println(err)
                    return
                }
                uu := u.String()
                var article Article
                c.BindJSON(&article)
                ins, err := db.Prepare("INSERT INTO articles(uuid, title,content) VALUES(?,?,?)")
                if err != nil {
                    log.Fatal(err)
                }
                ins.Exec(uu, article.TITLE, article.CONTENT)
    
                c.JSON(http.StatusOK, gin.H{"uuid": uu})
    
            })
            api.POST("/post/image", func(c *gin.Context) {
                creds := credentials.NewStaticCredentials(awsAccessKeyID, awsSecretAccessKey, token)
    
                cfg := aws.NewConfig().WithRegion("ap-northeast-1").WithCredentials(creds)
                svc := s3.New(session.New(), cfg)
    
                form, _ := c.MultipartForm()
    
                files := form.File["images[]"]
    
                var imageNames []ImageName
                imageName := ImageName{}
    
                for _, file := range files {
    
                    f, err := file.Open()
    
                    if err != nil {
                        log.Println(err)
                    }
    
                    defer f.Close()
    
                    size := file.Size
                    buffer := make([]byte, size)
    
                    f.Read(buffer)
                    fileBytes := bytes.NewReader(buffer)
                    fileType := http.DetectContentType(buffer)
                    path := "/media/" + file.Filename
                    params := &s3.PutObjectInput{
                        Bucket:        aws.String("article-s3-jpskgc"),
                        Key:           aws.String(path),
                        Body:          fileBytes,
                        ContentLength: aws.Int64(size),
                        ContentType:   aws.String(fileType),
                    }
                    resp, err := svc.PutObject(params)
    
                    fmt.Printf("response %s", awsutil.StringValue(resp))
    
                    imageName.NAME = file.Filename
    
                    imageNames = append(imageNames, imageName)
                }
    
                c.JSON(http.StatusOK, imageNames)
            })
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 metadata提取的PDF元数据,如何转换为一个Excel
  • ¥15 关于arduino编程toCharArray()函数的使用
  • ¥100 vc++混合CEF采用CLR方式编译报错
  • ¥15 coze 的插件输入飞书多维表格 app_token 后一直显示错误,如何解决?
  • ¥15 vite+vue3+plyr播放本地public文件夹下视频无法加载
  • ¥15 c#逐行读取txt文本,但是每一行里面数据之间空格数量不同
  • ¥50 如何openEuler 22.03上安装配置drbd
  • ¥20 ING91680C BLE5.3 芯片怎么实现串口收发数据
  • ¥15 无线连接树莓派,无法执行update,如何解决?(相关搜索:软件下载)
  • ¥15 Windows11, backspace, enter, space键失灵