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 u盘问题:盘符不显示 无媒体
  • ¥50 R语言读取nc按月均值转为tif
  • ¥30 智能车串级pid调参
  • ¥15 visual studio code翻译老是错误
  • ¥20 卫星测高数据的高程转换
  • ¥15 爬取招聘网站数据信息
  • ¥15 安装完tensorflow,import tensorflow as tf后报错,如何解决?
  • ¥15 ultralytics库导出onnx模型,模型失去预测能力
  • ¥15 linux下点对点协议连接2个USB串口的硬件流量控制问题
  • ¥15 SQL数据自动生成问题