Настройка заголовков HTTP

Я пытаюсь установить заголовок на моем веб-сервере Go. Я использую пакеты gorilla/mux и net/http.

Я хотел бы установить Access-Control-Allow-Origin: *, чтобы разрешить кросс-домен AJAX.

Здесь мой код Go:

func saveHandler(w http.ResponseWriter, r *http.Request) {
// do some stuff with the request data
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/save", saveHandler)
    http.Handle("/", r)
    http.ListenAndServe(":"+port, nil)
}

В пакете net/http есть документация, описывающая отправку заголовков HTTP-запросов, как если бы это был клиент - я не совсем уверен, как установить заголовки ответов?

Ответ 1

Ничего, я понял это - я использовал метод Set() на Header() (doh!)

Теперь мой обработчик выглядит следующим образом:

func saveHandler(w http.ResponseWriter, r *http.Request) {
    // allow cross domain AJAX requests
    w.Header().Set("Access-Control-Allow-Origin", "*")
}

Может быть, это поможет кому-то, когда кофеин лишен меня как-нибудь:)

Ответ 2

Все приведенные выше ответы неверны, поскольку они не могут обрабатывать запрос предварительной проверки OPTIONS, решение заключается в переопределении интерфейса маршрутизатора мультиплексора. См. Ошибка запроса urularJS $http с настраиваемым заголовком (все в CORS)

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/save", saveHandler)
    http.Handle("/", &MyServer{r})
    http.ListenAndServe(":8080", nil);

}

type MyServer struct {
    r *mux.Router
}

func (s *MyServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
    if origin := req.Header.Get("Origin"); origin != "" {
        rw.Header().Set("Access-Control-Allow-Origin", origin)
        rw.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
        rw.Header().Set("Access-Control-Allow-Headers",
            "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
    }
    // Stop here if its Preflighted OPTIONS request
    if req.Method == "OPTIONS" {
        return
    }
    // Lets Gorilla work
    s.r.ServeHTTP(rw, req)
}

Ответ 3

Не используйте '*' для Origin, пока вам не понадобится совершенно публичное поведение.
Как Wikipedia говорит:

"Значение" * "является особенным, поскольку оно не позволяет запросам предоставлять учетные данные, что означает HTTP-аутентификацию, SSL-сертификаты на стороне клиента и не разрешает куки файлы для отправки".

Это означает, что у вас будет много ошибок, особенно в Chrome, когда вы попытаетесь реализовать, например, простую аутентификацию.

Вот скорректированная оболочка:

// Code has not been tested.
func addDefaultHeaders(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if origin := r.Header.Get("Origin"); origin != "" {
            w.Header().Set("Access-Control-Allow-Origin", origin)
        }
        w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token")
        w.Header().Set("Access-Control-Allow-Credentials", "true")
        fn(w, r)
    }
}

И не забудьте ответить на все эти заголовки на запрос OPTIONS перед отправкой.

Ответ 4

Я создаю оболочку для этого случая:

func addDefaultHeaders(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        fn(w, r)
    }
}

Ответ 5

Установите правильное промежуточное ПО golang, чтобы вы могли повторно использовать любую конечную точку.

Тип и функция помощника

type Adapter func(http.Handler) http.Handler
// Adapt h with all specified adapters.
func Adapt(h http.Handler, adapters ...Adapter) http.Handler {
    for _, adapter := range adapters {
        h = adapter(h)
    }
    return h
}

Фактическое промежуточное ПО

func EnableCORS() Adapter {
    return func(h http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

            if origin := r.Header.Get("Origin"); origin != "" {
                w.Header().Set("Access-Control-Allow-Origin", origin)
                w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
                w.Header().Set("Access-Control-Allow-Headers",
                    "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
            }
            // Stop here if its Preflighted OPTIONS request
            if r.Method == "OPTIONS" {
                return
            }
            h.ServeHTTP(w, r)
        })
    }
}

Endpoint

Remeber! Middlewares применяются в обратном порядке (ExpectGET() получает пожары в первую очередь)

mux.Handle("/watcher/{action}/{device}",Adapt(api.SerialHandler(mux),
    api.EnableCORS(),
    api.ExpectGET(),
))

Ответ 6

Если вы не хотите переопределять свой маршрутизатор (если ваше приложение не настроено так, чтобы это поддерживалось, или вы хотите настроить CORS на маршруте по маршруту), добавьте обработчик OPTIONS для обработки запроса перед полетом,

То есть, с Gorilla Mux ваши маршруты будут выглядеть так:

accounts := router.Path("/accounts").Subrouter()
accounts.Methods("POST").Handler(AccountsCreate)
accounts.Methods("OPTIONS").Handler(AccountsCreatePreFlight)

Обратите внимание, что в дополнение к нашему обработчику POST мы определяем определенный обработчик метода OPTIONS.

А затем для фактической обработки метода предварительной проверки OPTIONS вы можете определить AccountsCreatePreFlight следующим образом:

// Check the origin is valid.
origin := r.Header.Get("Origin")
validOrigin, err := validateOrigin(origin)
if err != nil {
    return err
}

// If it is, allow CORS.
if validOrigin {
    w.Header().Set("Access-Control-Allow-Origin", origin)
    w.Header().Set("Access-Control-Allow-Methods", "POST")
    w.Header().Set("Access-Control-Allow-Headers",
        "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}

Что действительно заставило меня все это щелкнуть (помимо фактического понимания того, как работает CORS), так это то, что HTTP-метод предварительного запроса отличается от HTTP-метода реального запроса. Чтобы инициировать CORS, браузер отправляет предварительный запрос с HTTP-методом OPTIONS, который вы должны явно обработать в маршрутизаторе, а затем, если он получает соответствующий ответ "Access-Control-Allow-Origin": origin (или "*"). для всех) из вашего приложения, он инициирует фактический запрос.

Я также считаю, что вы можете делать "*" только для стандартных типов запросов (например, GET), но для других вам придется явно указать источник, как я делал выше.

Ответ 7

У меня была такая же проблема, как описано выше, приведенные выше решения верны, у меня установлено следующее: 1) Угловые для клиента 2) Структура Beego для сервера GO

Пожалуйста, следуйте этим пунктам 1) Настройки CORS должны быть включены только на сервере GO 2) НЕ добавляйте любые типы заголовков в angularJS, кроме этого

.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    }])

На сервере GO добавьте настройки CORS перед тем, как запрос начнет обрабатываться, чтобы запрос предварительной проверки получил 200 OK, после чего метод OPTIONS будет преобразован в GET, POST, PUT или когда-либо ваш тип запроса.

Ответ 8

Я знаю, что это другой поворот в ответе, но разве это не беспокоит веб-сервер? Например, nginx может помочь.

Модуль ngx_http_headers_module позволяет добавлять поля заголовка "Expires" и "Cache-Control" и произвольные поля в заголовок ответа

...

location ~ ^<REGXP MATCHING CORS ROUTES> {
    add_header Access-Control-Allow-Methods POST
    ...
}
...

Добавление nginx перед вашим сервисом в производстве кажется разумным. Он предоставляет гораздо больше возможностей для авторизации, регистрации и изменения запросов. Кроме того, он дает возможность контролировать, кто имеет доступ к вашей службе, и не только это, но можно указать другое поведение для определенных мест в вашем приложении, как показано выше.

Я мог бы рассказать о том, почему использовать веб-сервер с вашим api, но я думаю, что тема для другого обсуждения.