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



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



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



вот мой код:



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)
}


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

745   8  

8 ответов:

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

мой обработчик выглядит так:

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

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

все вышеприведенные ответы неверны, потому что они не справляются с запросом предварительного полета опций, решение состоит в том, чтобы переопределить интерфейс маршрутизатора mux. Смотрите AngularJS $http get request failed with custom header (alllowed in 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)
}

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

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

это означает, что вы получите много ошибок, особенно в 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)
    }
}

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

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

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)
    }
}

установите правильное промежуточное программное обеспечение 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)
        })
    }
}

точка

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

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

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

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

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

обратите внимание, что в дополнение к нашему обработчику сообщений, мы определяем конкретный обработчик метода 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, которые вы должны явно обрабатывать в своем маршрутизаторе, а затем, если он получает соответствующий ответ "Access-Control-Allow-Origin": origin (или "*" для всех) из своего приложения, он инициирует фактический запрос.

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

У меня была такая же проблема, как описано выше решения, приведенные выше, являются правильными, настройка у меня есть следующим образом 1) Разработка для клиента 2) основа похожа на любой для сервера

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

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

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

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

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

...

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

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

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

Comments

    Ничего не найдено.