You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GoLang转换curl多部分请求时遇文件扩展名错误求助

Fixing "File extension not allowed" Error in Documo Fax API Go Implementation

Let's break down why you're hitting that error even with a valid PDF file, and fix your code step by step.

Root Causes of the Error

  1. Redundant & Broken File Handling: Your original code reads the entire file into memory first, which moves the file pointer to the end—so the subsequent io.Copy does nothing. Plus, manually writing the file content as a string introduces unnecessary overhead and potential corruption risks.
  2. Mismatched Form Field Name: Your curl command uses an empty string as the file field name (-F '=@/path/to/file'), but your Go code uses "file" instead. Documo's API likely can't recognize the file when the field name doesn't match what it expects.
  3. Incorrect Authorization Header Format: Basic auth requires your API key to be base64-encoded as apiKey: (with an empty password), but your code uses a raw key directly.

Corrected Code

First, update the SendMultipartRequest function to fix these issues:

import (
    "bytes"
    "encoding/base64"
    "fmt"
    "io"
    "net/http"
    "net/http/httputil"
    "net/textproto"
)

func SendMultipartRequest(uri string, params map[string]string, files []*multipart.FileHeader, apiKey string) (*http.Request, error) {
    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)

    // Process files: use empty string as field name to match curl
    for _, fh := range files {
        file, err := fh.Open()
        if err != nil {
            return nil, fmt.Errorf("failed to open file %s: %w", fh.Filename, err)
        }
        defer file.Close()

        // Create form field with empty name (matches curl's `-F '=@file'` syntax)
        part, err := writer.CreateFormFile("", fh.Filename)
        if err != nil {
            return nil, fmt.Errorf("failed to create form entry for %s: %w", fh.Filename, err)
        }

        // Efficiently copy file content without reading entire file into memory
        if _, err := io.Copy(part, file); err != nil {
            return nil, fmt.Errorf("failed to copy content from %s: %w", fh.Filename, err)
        }
    }

    // Add form parameters
    for key, val := range params {
        if err := writer.WriteField(key, val); err != nil {
            return nil, fmt.Errorf("failed to write field %s: %w", key, err)
        }
    }

    // Close the writer to finalize the multipart boundary
    if err := writer.Close(); err != nil {
        return nil, fmt.Errorf("failed to close multipart writer: %w", err)
    }

    // Create the POST request
    req, err := http.NewRequest(http.MethodPost, uri, body)
    if err != nil {
        return nil, fmt.Errorf("failed to construct request: %w", err)
    }

    // Set correct content type for multipart form data
    req.Header.Set("Content-Type", writer.FormDataContentType())

    // Encode API key for Basic Authorization
    authEncoded := base64.StdEncoding.EncodeToString([]byte(apiKey + ":"))
    req.Header.Set("Authorization", "Basic "+authEncoded)

    return req, nil
}

Then update the SendFaxDocumo function with proper error handling and cleanup:

func SendFaxDocumo(files []*multipart.FileHeader, params map[string]string, apiKey string) {
    req, err := SendMultipartRequest("https://api.documo.com/v1/fax/send", params, files, apiKey)
    if err != nil {
        fmt.Printf("Request setup failed: %v\n", err)
        return
    }

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Printf("Request failed to send: %v\n", err)
        return
    }
    // Ensure response body is closed to prevent resource leaks
    defer resp.Body.Close()

    // Read response body
    respBody, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Failed to read response: %v\n", err)
        return
    }

    // Print response details for debugging
    fmt.Printf("Status Code: %d\n", resp.StatusCode)
    fmt.Printf("Response Headers:\n%v\n", resp.Header)
    fmt.Printf("Response Body:\n%s\n", string(respBody))
}

How to Use the Corrected Code

Here's an example of calling the function with your parameters:

func main() {
    // Assume you have your files ready (e.g., from an HTTP form upload)
    // For testing, you could construct a multipart.FileHeader manually, or use form data
    params := map[string]string{
        "recipientFax":  "12345678900",
        "coverPage":     "false",
        "recipientName": "John",
        "subject":       "test",
        "notes":         "test",
    }
    yourApiKey := "YOUR_ACTUAL_DOCUMO_API_KEY"
    
    // Replace `files` with your actual file list
    SendFaxDocumo(files, params, yourApiKey)
}

Key Fixes Explained

  • File Handling: We use io.Copy directly to stream the file content to the multipart writer, avoiding unnecessary memory usage and file pointer issues.
  • Field Name Match: Using an empty string for the file field name aligns with your original curl command, ensuring Documo's API recognizes the uploaded file.
  • Proper Auth: We correctly encode the API key for Basic Authorization, which is required by Documo's API (even if your original error wasn't auth-related, this prevents future issues).
  • Robust Error Handling: Every error is wrapped with context and returned immediately, preventing invalid execution flow.

内容的提问来源于stack exchange,提问作者Anam Shah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:30:37