Headers

ctx.Request.Headers provides access to HTTP headers sent by the client during the current request.

The headers contain additional information about the request, such as the type of content, user agent, accepted languages or any custom header sent by the client.

This object only allows to consult the headers received from the client. To manage the headers that will be sent to the client uses Response Headers.

gox
func GET(ctx *gox.Context) gox.Page {
    userAgent, ok := ctx.Request.Headers.Get("User-Agent")

    if !ok {
        return <p>Unknown client</p>
    }

    return <p>{{ userAgent }}</p>
}

Structure

ctx.Request.Headers implement the following API:

text
Headers
{
    Get(key string) (string, bool)
    GetAll(key string) ([]string, bool)
    Has(key string) bool
    IsEmpty() bool
    Count() int
    Keys() []string
    Values() []string
    Entries() map[string][]string
}

All methods are read only.

Header searches do not distinguish between capital letters and lower letters.


Methods

MethodDescription
Get()Returns the first value associated with a header.
GetAll()Returns all values associated with a header.
Has()It indicates if a header exists.
IsEmpty()It indicates whether the collection contains headers.
Count()Returns the number of headers available.
Keys()Returns all the keys to the collection.
Values()Returns the first value associated with each header.
Entries()Returns all headers along with all associated values.

Get()

Firma:func (Headers) Get(key string) (string, bool)

Get() returns the first value associated with a header and indicates whether the header exists.

gox
func GET(ctx *gox.Context) gox.Page {
    userAgent, ok := ctx.Request.Headers.Get("User-Agent")

    // ok == true
    // userAgent == "Mozilla/5.0..."
    return <p>{{ userAgent }}</p>
}

When the header does not exist, it returns an empty string and false.

gox
func GET(ctx *gox.Context) gox.Page {
    traceID, ok := ctx.Request.Headers.Get("X-Trace-ID")

    if !ok {
        return <p>Trace ID not found</p>
    }

    return <p>{{ traceID }}</p>
}

When a header contains several values, Get() return only the first one.

Use Get() when you only need the first value associated with a header.


GetAll()

Firma:func (Headers) GetAll(key string) ([]string, bool)

GetAll() returns all the values associated with a header and indicates whether the header exists.

gox
func GET(ctx *gox.Context) gox.Page {
    accept, ok := ctx.Request.Headers.GetAll("Accept")

    if !ok {
        return <p>Accept header not found</p>
    }

    return <ul>
        <:for value range={{ accept }}>
            <li>{{ value }}</li>
        </:for>
    </ul>
}

When the header does not exist or contains values, it returns nil and false.

gox
func GET(ctx *gox.Context) gox.Page {
    languages, ok := ctx.Request.Headers.GetAll("Accept-Language")

    // languages == nil
    // ok == false

    if !ok {
        return <p>No preferred languages</p>
    }

    return <ul>
        <:for language range={{ languages }}>
            <li>{{ language }}</li>
        </:for>
    </ul>
}

The returned slice is a separate copy. Modifying it does not change the original headers of the request.

gox
func GET(ctx *gox.Context) gox.Page {
    values, ok := ctx.Request.Headers.GetAll("Accept")

    if !ok {
        return <p>Accept header not found</p>
    }

    values[0] = "modified"

    original, _ := ctx.Request.Headers.Get("Accept")

    // original conserva el valor recibido del cliente
    return <p>{{ original }}</p>
}

Use this method when a header can have several values within the same request.


Has()

Firma:func (Headers) Has(key string) bool

Has() indicates whether a header exists and contains at least one value.

gox
func GET(ctx *gox.Context) gox.Page {
    if ctx.Request.Headers.Has("Authorization") {
        return <p>Authorized request</p>
    }

    return <p>Anonymous request</p>
}

Has() It only checks the existence of the header. It does not value or interpret its content.

Use Has() when you only need to check the existence of a header.

When you also need to see its value, use it directly Get() to avoid looking for the same header twice.

gox
func GET(ctx *gox.Context) gox.Page {
    authorization, ok := ctx.Request.Headers.Get("Authorization")

    if !ok {
        return <p>Anonymous request</p>
    }

    return <p>{{ authorization }}</p>
}

IsEmpty()

Firma:func (Headers) IsEmpty() bool

IsEmpty() indicates whether the collection does not contain headers with values.

gox
func GET(ctx *gox.Context) gox.Page {
    if ctx.Request.Headers.IsEmpty() {
        return <p>No headers</p>
    }

    return <p>Headers available</p>
}

Under normal conditions, an HTTP request usually contains several headers.


Count()

Firma:func (Headers) Count() int

Count() returns the number of headers available.

gox
func GET(ctx *gox.Context) gox.Page {
    total := ctx.Request.Headers.Count()

    return <p>{{ total }}</p>
}

Each header name counts as a single element, although it has several associated values.

For example, a header with three values continues to count as a single header.


Keys()

Firma:func (Headers) Keys() []string

Keys() returns all the keys present in the collection.

gox
func GET(ctx *gox.Context) gox.Page {
    keys := ctx.Request.Headers.Keys()

    return <ul>
        <:for key range={{ keys }}>
            <li>{{ key }}</li>
        </:for>
    </ul>
}

Each header name appears only once, even if it has several associated values.

The returned slice is a separate copy and can be modified without altering the request headers.


Values()

Firma:func (Headers) Values() []string

Values() returns the first value associated with each header.

gox
func GET(ctx *gox.Context) gox.Page {
    values := ctx.Request.Headers.Values()

    return <ul>
        <:for value range={{ values }}>
            <li>{{ value }}</li>
        </:for>
    </ul>
}

When a header contains several values, only the first one is included.

Values() only returns the values and does not retain the relationship to the name of each header.

If you need to keep all the values associated with each header, use Entries().

The returned slice is a separate copy and can be modified without altering the request.


Entries()

Firma:func (Headers) Entries() map[string][]string

Entries() returns all headers along with all their values.

gox
func GET(ctx *gox.Context) gox.Page {
    headers := ctx.Request.Headers.Entries()

    // headers["Accept"]
    // headers["User-Agent"]
    // headers["Authorization"]
    return <p>{{ len(headers) }}</p>
}

Each map key represents the name of a header and contains all associated values.

gox
func GET(ctx *gox.Context) gox.Page {
    headers := ctx.Request.Headers.Entries()

    return <ul>
        <:for key, values range={{ headers }}>
            <li>
                <strong>{{ key }}</strong>

                <ul>
                    <:for value range={{ values }}>
                        <li>{{ value }}</li>
                    </:for>
                </ul>
            </li>
        </:for>
    </ul>
}

Both the map and its slices are independent copies. Modifying them does not change the original headers of the request.

gox
func GET(ctx *gox.Context) gox.Page {
    headers := ctx.Request.Headers.Entries()

    headers["Accept"][0] = "modified"
    headers["X-Custom"] = []string{"example"}

    accept, _ := ctx.Request.Headers.Get("Accept")
    hasCustom := ctx.Request.Headers.Has("X-Custom")

    // accept conserva el valor recibido del cliente
    // hasCustom == false
    return <p>{{ accept }}</p>
}

Use Entries() when you need to go through the complete collection by preserving the relationship between each header and its values.


Headers with empty values

The signature of Get() allows to distinguish between an absent header and a present header whose value is an empty string.

A header with no content:

text
X-Custom:

produce:

gox
func GET(ctx *gox.Context) gox.Page {
    value, ok := ctx.Request.Headers.Get("X-Custom")

    // value == ""
    // ok == true
    return <p>{{ value }}</p>
}

When the header was not sent:

gox
func GET(ctx *gox.Context) gox.Page {
    value, ok := ctx.Request.Headers.Get("X-Custom")

    // value == ""
    // ok == false
    return <p>{{ value }}</p>
}

This difference makes it possible to determine whether the client omitted the header or sent it explicitly with an empty value.


Full example

The following example shows several common operations on the headers of an request:

gox
func GET(ctx *gox.Context) gox.Page {
    headers := ctx.Request.Headers

    userAgent, hasUserAgent := headers.Get("User-Agent")
    accept, hasAccept := headers.GetAll("Accept")
    keys := headers.Keys()

    if !hasUserAgent {
        userAgent = "Unknown client"
    }

    return <main>
        <p>User-Agent: {{ userAgent }}</p>
        <p>Total headers: {{ headers.Count() }}</p>
        <p>Authorization: {{ headers.Has("Authorization") }}</p>

        <h2>Accept</h2>

        <:if !hasAccept>
            <p>Accept header not found</p>
        <:else>
            <ul>
                <:for value range={{ accept }}>
                    <li>{{ value }}</li>
                </:for>
            </ul>
        </:if>

        <h2>Header names</h2>

        <ul>
            <:for key range={{ keys }}>
                <li>{{ key }}</li>
            </:for>
        </ul>
    </main>
}

Best practices

  • Use Get() when you only need the first value of a header.
  • Check the boolean value returned by Get() when the header may not exist.
  • Use GetAll() for headers that may contain several values.
  • Check the boolean value returned by GetAll() before using the slice.
  • Use Has() when you only need to check the existence of a header.
  • When you also need the value, use it directly Get() to avoid consulting the collection twice.
  • Use Values() when you only need to go through the first value of each header.
  • Use Entries() when you need to keep the relationship between each header and all its values.
  • It avoids assuming that all headers contain a single value.
  • It avoids relying on the capitalization used by the client when sending the name of a header.
  • Do not use headers received from the client as reliable values without previously validating them.
  • Valid especially headers related to authentication, proxies, IP addresses and readdresses.

To learn more about RequestSee your documentation. To learn more about CookiesSee your documentation. To learn more about QuerySee your documentation. To learn more about FormSee your documentation. To learn more about Context, check your documentation.


See also

Next step

Continue with the documentation for Cookies to learn how to access cookies sent by the client.

Cookies