使用Pinata API上传文件
2024/10/22 3:03:19
本文主要是介绍使用Pinata API上传文件,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
这是对Pinata 挑战的提交_
我建造的东西我使用Golang和React构建了一个可以上传多个文件的工具,它可以上传多个到Pinata。
以下是它的功能分解。
- 它检查请求是否使用POST方法。如果不是,它将发送一个状态码为405(方法不允许的方法)的错误响应并返回。
- 它使用ParseMultipartForm函数解析请求中的多部分表单数据,最大文件大小为maxFileSize。如果解析表单数据时出错,它将发送一个状态码为400(错误请求)的错误响应并返回。
- 它从请求中使用MultipartForm.File["files"]获取上传的文件列表。如果没有上传文件,它将发送一个状态码为400(错误请求)的错误响应并返回。
- 它初始化了两个切片:responses用于存储成功的上传,errors用于存储上传过程中出现的任何错误。
- 它创建了一个sync.WaitGroup和一个sync.Mutex以同步并发文件上传。
- 它遍历每个上传的文件并为每个文件启动一个goroutine以使用uploadFileToPinata函数进行上传。wg.Add(1)增加了等待组计数器,在goroutine完成时使用defer wg.Done()减少计数器。
- uploadFileToPinata函数将每个文件上传到Pinata API端点并返回响应及上传过程中出现的任何错误。
- mu.Lock()和mu.Unlock()调用确保对responses和errors切片的更新是原子操作。
- 所有的goroutines完成后,该函数使用wg.Wait()等待它们完成。
- 它构造了一个JSON响应结构体result,包含成功的上传和错误。
- 它将响应头的内容类型设置为JSON。
- 它检查是否有错误。如果有错误,它将响应状态码设置为206(部分内容)。否则,将状态码设置为200(OK)。
- 它将结果结构体编码为JSON并将其写入响应体。
总体来说,这段代码负责处理文件上传的过程,执行并行上传,并发送一个包含成功上传的文件以及过程中出现的任何错误信息的JSON响应。
演示版如图所示
我的代码访问 Github 查看更多详情。
package main import ( "bytes" "encoding/json" "fmt" "io" "log" "mime/multipart" "net/http" "os" "path/filepath" "sync" "github.com/joho/godotenv" ) const ( maxFileSize = 10 << 20 // 10 MB ) type PinataResponse struct { IpfsHash string `json:"IpfsHash"` PinSize int `json:"PinSize"` Timestamp string `json:"Timestamp"` } type ErrorResponse struct { Error string `json:"error"` } type Credentials struct { Username string `json:"username"` Password string `json:"password"` } func main() { // 加载 .env 文件失败 err := godotenv.Load(".env") if err != nil { log.Fatal("加载 .env 文件失败") } // http.HandleFunc("/upload", handleUpload) http.Handle("/upload", corsMiddleware(http.HandlerFunc(handleUpload))) fmt.Println("服务运行在 http://localhost:9000") log.Fatal(http.ListenAndServe(":9000", nil)) } func corsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, pinata_api_key, pinata_secret_api_key") if r.Method == "OPTIONS" { w.WriteHeader(http.StatusNoContent) return } next.ServeHTTP(w, r) }) } func handleUpload(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { sendErrorResponse(w, "方法不允许", http.StatusMethodNotAllowed) return } err := r.ParseMultipartForm(maxFileSize) if err != nil { sendErrorResponse(w, "解析多部分表单错误: "+err.Error(), http.StatusBadRequest) return } files := r.MultipartForm.File["files"] if len(files) == 0 { sendErrorResponse(w, "没有上传任何文件", http.StatusBadRequest) return } responses := make([]PinataResponse, 0, len(files)) errors := make([]string, 0) var wg sync.WaitGroup var mu sync.Mutex for _, fileHeader := range files { wg.Add(1) go func(fh *multipart.FileHeader) { defer wg.Done() response, err := uploadFileToPinata(fh) mu.Lock() defer mu.Unlock() if err != nil { errors = append(errors, fmt.Sprintf("上传 %s 时出错: %v", fh.Filename, err)) } else { responses = append(responses, response) } }(fileHeader) } wg.Wait() result := struct { SuccessfulUploads []PinataResponse `json:"successful_uploads"` Errors []string `json:"errors,omitempty"` }{ SuccessfulUploads: responses, Errors: errors, } w.Header().Set("Content-Type", "application/json") if len(errors) > 0 { w.WriteHeader(http.StatusPartialContent) } else { w.WriteHeader(http.StatusOK) } json.NewEncoder(w).Encode(result) } func uploadFileToPinata(fileHeader *multipart.FileHeader) (PinataResponse, error) { file, err := fileHeader.Open() if err != nil { return PinataResponse{}, fmt.Errorf("无法打开文件: %w", err) } defer file.Close() var requestBody bytes.Buffer writer := multipart.NewWriter(&requestBody) part, err := writer.CreateFormFile("file", filepath.Base(fileHeader.Filename)) if err != nil { return PinataResponse{}, fmt.Errorf("无法创建表单文件: %w", err) } _, err = io.Copy(part, file) if err != nil { return PinataResponse{}, fmt.Errorf("无法复制文件内容: %w", err) } err = writer.Close() if err != nil { return PinataResponse{}, fmt.Errorf("无法关闭多部分写入器: %w", err) } // 加载环境变量 pinataAPIKey := os.Getenv("PINATA_API_KEY") pinataAPISecret := os.Getenv("PINATA_API_SECRET") pinataAPIURL := os.Getenv("PINATA_API_URL") req, err := http.NewRequest("POST", pinataAPIURL, &requestBody) if err != nil { return PinataResponse{}, fmt.Errorf("无法创建请求: %w", err) } req.Header.Set("Content-Type", writer.FormDataContentType()) req.Header.Set("pinata_api_key", pinataAPIKey) req.Header.Set("pinata_secret_api_key", pinataAPISecret) client := &http.Client{} resp, err := client.Do(req) if err != nil { return PinataResponse{}, fmt.Errorf("无法发送请求: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return PinataResponse{}, fmt.Errorf("Pinata API 返回非 OK 状态: %s", resp.Status) } var pinataResp PinataResponse err = json.NewDecoder(resp.Body).Decode(&pinataResp) if err != nil { return PinataResponse{}, fmt.Errorf("无法解析Pinata响应: %w", err) } return pinataResp, nil } func sendErrorResponse(w http.ResponseWriter, message string, statusCode int) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) json.NewEncoder(w).Encode(ErrorResponse{Error: message}) }
全屏, 退出全屏
在共享的GitHub主页上找前端代码
了解更多详情这篇关于使用Pinata API上传文件的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-10设计团队的高效协作:如何利用项目管理软件优化流程
- 2025-01-10如何在远程团队中实现任务可视化和进度跟踪
- 2025-01-10提高设计项目透明度:可视化管理工具如何帮助提升质量
- 2025-01-09如何用项目管理软件提升电商平台的运营效率和团队协作
- 2025-01-09电商转型的技术赋能:大数据与云计算的无缝连接
- 2025-01-09个性化服务与客户忠诚度:电商平台的CRM应用
- 2025-01-09电商数据分析的核心应用:提升销售、优化管理
- 2025-01-09春节跨境电商多团队协作难?板栗看板让你的团队忙而不乱
- 2025-01-08给 Postgres 写一个向量插件 - 向量类型
- 2025-01-08高效短剧档期管理技巧,如何选择合适的软件?