zoukankan      html  css  js  c++  java
  • Golang HTTP文件上传

    2018年02月08日 10:07:13  阅读数:346 标签: golang HTTP 文件上传

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lengyuezuixue/article/details/79277691

       首先,我们在服务器端设定两个路由,/upload用于文件上传,/files/*用于文件下载。

    1.  
      const maxUploadSize = 2 * 1024 * 2014 // 2 MB
    2.  
      const uploadPath = "./tmp"
    3.  
       
    4.  
      func main() {
    5.  
      http.HandleFunc("/upload", uploadFileHandler())
    6.  
       
    7.  
      fs := http.FileServer(http.Dir(uploadPath))
    8.  
      http.Handle("/files/", http.StripPrefix("/files", fs))
    9.  
       
    10.  
      log.Print("Server started on localhost:8080, use /upload for uploading files and /files/{fileName} for downloading files.")
    11.  
      log.Fatal(http.ListenAndServe(":8080", nil))
    12.  
      }
       我们还将要上传的目标目录,以及我们接受的最大文件大小定义为常量。注意这里,整个文件服务的概念是如此的简单--我们仅使用标准库中的工具,使用http.FileServer创建一个HTTP处理程序,它将使用http.Dir(uploadPath)提供的目录来上传文件。

      现在我们只需要实现uploadFileHander.这个处理程序将包含以下功能:

           ·验证文件最大值;

           ·从请求验证文件和POST参数

           ·检查所提供的文件类型

           ·创建一个随机文件名

           ·将文件写入硬盘

           ·处理所有错误,如果一切顺利返回成功消息

       第一步,我们定义处理程序:

    1.  
      func uploadFileHandler() http.HandlerFunc {
    2.  
      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
       然后,我们使用http.MaxBytesReader验证文件大小,当文件大小大于设定值时它将返回一个错误。错误将被一个助手程序renderError进行处理,它返回错误信息以及对应的HTTP状态码。
    1.  
      r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
    2.  
      if err := r.ParseMultipartForm(maxUploadSize); err != nil {
    3.  
      renderError(w, "FILE_TOO_BIG", http.StatusBadRequest)
    4.  
      return
    5.  
      }
       如果文件大小验证通过,我们将检查并解析表单参数类型和上传的文件,并读取文件。在本例中,wield清晰起见,我们不使用花哨的io.Reader和io.Writer接口,我们只是简单的将文件读取到一个字节数组中,这点我们后面会写到。
    1.  
      fileType := r.PostFormValue("type")
    2.  
      file, _, err := r.FormFile("uploadFile")
    3.  
      if err != nil {
    4.  
      renderError(w, "INVALID_FILE", http.StatusBadRequest)
    5.  
      return
    6.  
      }
    7.  
      defer file.Close()
    8.  
      fileBytes, err := ioutil.ReadAll(file)
    9.  
      if err != nil {
    10.  
      renderError(w, "INVALID_FILE", http.StatusBadRequest)
    11.  
      return
    12.  
      }
       现在我们成功的验证了文件的大小,并读取了文件,接下来我们该检验文件的类型了。一种廉价但是并不安全的方式,只检查文件扩展名,并相信用户没有改变它,但是对于一个正式的项目来说并不应该这么做。

      幸运的是,Go标准库提供给我们一个Http.DetectConntectType函数,这个函数基于mimesniff算法,祝需要读取文件的512个字节就能够判断文件的类型。

    1.  
      iletype := http.DetectContentType(fileBytes)
    2.  
      if filetype != "image/jpeg" && filetype != "image/jpg" &&
    3.  
      filetype != "image/gif" && filetype != "image/png" &&
    4.  
      filetype != "application/pdf" {
    5.  
      renderError(w, "INVALID_FILE_TYPE", http.StatusBadRequest)
    6.  
      return
    7.  
      }
       在实际应用程序中,我们可能会使用文件元数据做一些事情,例如将其保存到数据库或将其推送到外部服务--以任何方式,我们将解析和操作元数据。这里我们创建一个随机的新名字并将新文件名记录下来。
    1.  
      fileName := randToken(12)
    2.  
      fileEndings, err := mime.ExtensionsByType(fileType)
    3.  
      if err != nil {
    4.  
      renderError(w, "CANT_READ_FILE_TYPE", http.StatusInternalServerError)
    5.  
      return
    6.  
      }
    7.  
      newPath := filepath.Join(uploadPath, fileName+fileEndings[0])
    8.  
      fmt.Printf("FileType: %s, File: %s ", fileType, newPath)
       马上就大功告成了,只剩下一个关键步骤-写文件。如上文提供的,我们只需要复制读取的二进制文件到新创建的名为newFile的文件处理程序中。

       如果所有部分都没问题,我们给用户返回一个i额SUCCESS信息。

    1.  
      newFile, err := os.Create(newPath)
    2.  
      if err != nil {
    3.  
      renderError(w, "CANT_WRITE_FILE", http.StatusInternalServerError)
    4.  
      return
    5.  
      }
    6.  
      defer newFile.Close()
    7.  
      if _, err := newFile.Write(fileBytes); err != nil {
    8.  
      renderError(w, "CANT_WRITE_FILE", http.StatusInternalServerError)
    9.  
      return
    10.  
      }
    11.  
      w.Write([]byte("SUCCESS"))
       这样就可以了。你可对这个简单的例子进行测试,使用虚拟的文件上传HTML页面,cURL或工具例如postman。
  • 相关阅读:
    软件工程学习总结
    南通大学教务管理系统微信平台 用户体验
    设计一款适合父母使用的手机
    我想搞懂的软工问题
    C++用法的学习心得
    email program (客户端)演变过程有感
    C++用法的学习心得
    软件工程学期总结
    微信南通大学教务学生管理系统_用户体验
    设计一款给父母使用的手机
  • 原文地址:https://www.cnblogs.com/williamjie/p/9667270.html
Copyright © 2011-2022 走看看