Проверка user-agent

Возникла необходимость проверить, откуда пользователь делает запрос, чтобы определить, каким способом дать ему ответ(дать html в браезер или JSON в, например, curl). Знаю, что html можно дать и в curl, но это будет неудобоваримо.

Погуглив, узнал, что нет какого-то "железного" способа определить, делается ли запрос из браузера. Но есть некая закономерность в юзерагентах браузеров. Написал мини-функцию и хочу спросить мнения, является ли она хоть сколь-либо надежной, для определения пришел пользователь из браузера или нет и почитать мнение, как можно надежнее определить это. Вот функция:

func GetRequest(w http.ResponseWriter, r *http.Request) {
    ua := r.Header.Get("User-Agent")
    switch true {
    case strings.Contains(ua, "Mozilla"):
        w.Write([]byte("Browser" + "\n"))
        return
    case strings.Contains(ua, "Gecko"):
        w.Write([]byte("Browser" + "\n"))
        return
    default:
        w.Write([]byte("Rest quester" + "\n"))
    }
}

Добавил еще такой кейс

case strings.Contains(ua, "Opera"):
        w.Write([]byte("Browser" + "\n"))
        return

Ответы (2 шт):

Автор решения: Andrey Mironov

Попробуйте использовать существующие пакеты для парсинга User-Agent, например https://github.com/mileusna/useragent, https://github.com/mssola/user_agent или https://github.com/ua-parser/uap-go. Данные пакеты позволяют определить тип браузера, операционную систему, тип устройства и т.д.

Вот пример с перехватом четрыех браузеров (в пакете доступно больше):

package main

import (
    "github.com/mileusna/useragent"
    "log"
    "net/http"
)

func GetRequest(w http.ResponseWriter, r *http.Request) {
    useragent := r.Header.Get("User-Agent")
    parsed := ua.Parse(useragent)

    if parsed.Name == ua.Chrome || parsed.Name == ua.Opera || parsed.Name ==ua.Firefox || parsed.Name == ua.Safari {
        // вернуть HTML
    } else {
        // вернуть JSON
    }
}

func main() {
    http.HandleFunc("/", GetRequest)
    log.Fatal(http.ListenAndServe(":8000", nil))
}

В можете перечислить в if все браузеры, которые заданны в данном пакете. Таким образом вы покроете абсолютное большинство запросов (за исключением кастомных браузеров).

→ Ссылка
Автор решения: KoVadim

Я думаю, что Ваш подход очень необычен. А что если я в curl хочу получать текст? Или в браузере получать данные в виде json? Но человечество нашло выход.

Самый простой и наивный способ - кодировать тип желаемого результата в самом запросе. Ведь если url/uri содержит index.html, то очевидно, что хотят получить текст в виде html, а если там data.json, то явно не xml ожидают. Этот подход очень "нативный" и "ожидаемый".

Второй способ - клиент явно декларирует в запросе, что он хочет использует для этого заголовок Accept: text/plain (или что именно нужно)

[зачеркнуто] Content-Type может быть не только в ответе, а и в запросе. Вот есть пример https://stackoverflow.com/questions/56722602/golang-http-server-return-html-or-json-depending-on-content-type [/зачеркнуто]

→ Ссылка