Introduction
The http.Request
struct represents an incoming HTTP request. It's the primary way your server receives information about a client's request. Understanding its fields and methods is crucial for building robust web applications with Go.
Struct Definition
The http.Request
struct is defined in the net/http
package. Here's a simplified view of its key fields:
type Request struct {
Method string
URL *url.URL
Proto string
ProtoMajor, ProtoMinor int
Header Header
Body io.ReadCloser
GetBody func() (io.ReadCloser, error)
ContentLength int64
TransferEncoding []string
Close bool
Form url.Values
PostForm url.Values
MultipartForm *multipart.Form
RemoteAddr string
RequestURI string
// ... other fields
}
Common Fields
Method
The HTTP method of the request, such as GET
, POST
, PUT
, DELETE
, etc. It's typically uppercase.
req.Method
URL
A pointer to a url.URL
struct, which contains the parsed components of the request URL (scheme, host, path, query parameters, etc.).
req.URL
You can access components like:
req.URL.Path
: The path component of the URL.req.URL.RawQuery
: The raw query string.req.URL.Query()
: Returns aurl.Values
map of parsed query parameters.
Proto
The HTTP protocol version used for the request (e.g., HTTP/1.1
, HTTP/2.0
).
req.Proto
Header
An http.Header
type, which is a map of string keys to string slices. It represents the request headers.
req.Header
Example: Accessing the User-Agent
header:
userAgent := req.Header.Get("User-Agent")
Body
An io.ReadCloser
interface representing the request body. For methods like POST
or PUT
, this is where you'd read data sent by the client.
bodyBytes, err := io.ReadAll(req.Body)
Important: The Body
must be closed after reading to release resources.
defer req.Body.Close()
Form
A url.Values
map containing the parsed form data. This is populated after calling ParseForm()
. It includes both URL query parameters and form values from the request body (for POST
requests with application/x-www-form-urlencoded
content type).
formValue := req.Form.Get("myParam")
PostForm
A url.Values
map specifically containing form values from the request body. This is also populated after calling ParseForm()
and is useful when distinguishing between query parameters and body form data.
postFormValue := req.PostForm.Get("myField")
RemoteAddr
The network address that sent the request, in the form "host:port"
.
clientIP := req.RemoteAddr
Context
A context.Context
value associated with the request. This is crucial for managing request-scoped values, cancellation signals, and deadlines.
ctx := req.Context()
Common Methods
ParseForm()
This method parses the request body and URL values into the Form
and PostForm
maps. It's essential to call this if you need to access form data from POST
requests or query parameters.
err := req.ParseForm()
if err != nil {
// Handle error
}
// Now req.Form and req.PostForm are populated
ParseForm()
also handles multipart/form-data
requests, populating req.MultipartForm
.
ParseMultipartForm()
A more specific method to parse multipart/form-data
requests. It takes a maximum memory limit as an argument.
maxMemory := int64(10 << 20) // 10 MB
err := req.ParseMultipartForm(maxMemory)
if err != nil {
// Handle error
}
// Access files and fields via req.MultipartForm
Reading the Body
The request body is an io.ReadCloser
. You typically use io.ReadAll
or read in chunks. Remember to always close the body.
defer req.Body.Close()
bodyBytes, err := io.ReadAll(req.Body)
if err != nil {
// Handle error
}
bodyString := string(bodyBytes)
// Process bodyString
Getting Header Values
The Header.Get(key)
method is the preferred way to retrieve a header value. It returns the first value associated with the key, or an empty string if the key is not present.
contentType := req.Header.Get("Content-Type")
For multiple values or checking for presence, use req.Header.Values(key)
and req.Header.Contains(key)
.
Example Usage
Here's a simple Go HTTP handler demonstrating how to access request details:
package main
import (
"fmt"
"io"
"log"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
// Accessing request details
method := r.Method
path := r.URL.Path
userAgent := r.Header.Get("User-Agent")
clientIP := r.RemoteAddr
fmt.Fprintf(w, "Request Details
")
fmt.Fprintf(w, "Method: %s
", method)
fmt.Fprintf(w, "Path: %s
", path)
fmt.Fprintf(w, "User-Agent: %s
", userAgent)
fmt.Fprintf(w, "Remote Address: %s
", clientIP)
// Reading the request body (for POST, PUT, etc.)
if r.Body != nil {
defer r.Body.Close()
bodyBytes, err := io.ReadAll(r.Body)
if err != nil {
log.Printf("Error reading request body: %v", err)
http.Error(w, "Error reading request body", http.StatusInternalServerError)
return
}
if len(bodyBytes) > 0 {
fmt.Fprintf(w, "Request Body:
")
fmt.Fprintf(w, "%s
", string(bodyBytes))
} else {
fmt.Fprintf(w, "Request Body: (empty)
")
}
} else {
fmt.Fprintf(w, "Request Body: (none)
")
}
// Parsing form data (if content type is appropriate)
err := r.ParseForm()
if err != nil {
log.Printf("Error parsing form: %v", err)
// Continue processing if form parsing fails, but log the error
} else {
if len(r.Form) > 0 {
fmt.Fprintf(w, "Form Data
")
for key, values := range r.Form {
fmt.Fprintf(w, "%s: %v
", key, values)
}
}
}
}
func main() {
http.HandleFunc("/ms/docs/net/http/request", handler)
log.Println("Server starting on :8080...")
log.Fatal(http.ListenAndServe(":8080", nil))
}