Verified Solution

[StackOverflow/go] golang POST image and text field with multipart/form-data

Sponsored Content
### ROOT CAUSE The issue arises when attempting to send a multipart/form-data request in Go with both text and image data. The root cause is the lack of proper handling of multipart form data creation, specifically: 1. **Missing multipart.Writer**: Without creating a multipart.Writer, the request cannot properly structure binary and text parts. 2. **Incorrect Content-Type**: The Content-Type header is not set to the correct multipart/form-data value with the appropriate boundary. 3. **File Handling**: The image file is not being read and attached as a form part, leading to missing or corrupted data. ### CODE FIX ```go package main import ( "bytes" "fmt" "mime/multipart" "net/http" "os" "io" ) func uploadHandler(w http.ResponseWriter, r *http.Request) { // Create multipart writer body := &bytes.Buffer{} wr := multipart.NewWriter(body) // Add text field part, err := wr.CreateFormFile("text_field", "data.txt") if err != nil { http.Error(w, "Error creating text part", http.StatusInternalServerError) return } part.Write([]byte("Sample text content")) if err := part.Close(); err != nil { http.Error(w, "Error writing text part", http.StatusInternalServerError) return } // Add image file file, header := r.FormFile("image_field") defer file.Close() part, err = wr.CreateFormFile("image_field", header.Filename) if err != nil { http.Error(w, "Error creating image part", http.StatusInternalServerError) return } if _, err := io.Copy(part, file); err != nil { http.Error(w, "Error reading image file", http.StatusInternalServerError) return } if err := part.Close(); err != nil { http.Error(w, "Error closing image part", http.StatusInternalServerError) return } // Close multipart writer and set headers if err := wr.Close(); err != nil { http.Error(w, "Error closing multipart writer", http.StatusInternalServerError) return } // Send response with image URL url := fmt.Sprintf("http://example.com/uploads/%s", header.Filename) fmt.Fprintf(w, "Upload successful! Image URL: %s", url) // Handle file saving (example using os.Create) saveFile, err := os.Create(fmt.Sprintf("/path/to/save/%s", header.Filename)) if err != nil { http.Error(w, "Error saving file", http.StatusInternalServerError) return } defer saveFile.Close() io.Copy(saveFile, file) } ``` **Client-Side Example (POST Request)**: ```go body := &bytes.Buffer{} writer := multipart.NewWriter(body) part, err := writer.CreateFormFile("text_field", "data.txt") if err := part.Write([]byte("Hello, World!")); err != nil { /* handle error */ } if _, err := writer.CreateFormFile("image_field", "image.jpg"); err != nil { /* handle error */ } writer.Close() req, err := http.NewRequest("POST", "http://example.com/upload", body) if err != nil { /* handle error */ } req.Header.Set("Content-Type", writer.FormDataContentType()) // Send request with http.Client ``` **Key Fixes**: 1. **multipart.Writer**: Properly structures form data with boundaries. 2. **File Handling**: Uses `r.FormFile` to read uploaded files and copies them to the form part. 3. **Content-Type**: Automatically generates the correct boundary with `w.FormDataContentType()`. 4. **Error Handling**: Checks each step to handle potential failures.
Deploy on DigitalOcean ($200 Credit)

Related Fixes

[StackOverflow/reactjs] change Emmet abbreviation ".." from 'styleName' to 'className'
[StackOverflow/rust] How do I make asynchronous parallel requests in a separate thread?
[rust-lang/rust] [ICE]: `type variables should not be hashed`