Как обрабатывать запросы preflight CORS на сервере Go

поэтому я пишу этот RESTful backend в Go, который будет вызываться с помощью межсайтовых HTTP-запросов, т. е. из контента, обслуживаемого другим сайтом (на самом деле, просто другой порт, но политика того же происхождения, так что мы здесь).

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

мой вопрос заключается в том, как лучше всего справиться и адекватно ответить на эти предполетные запросы в Go контекст. То, как я задумал, не кажется мне очень элегантным, и я задаюсь вопросом, есть ли какой-то другой подход к этому, о котором я не думал.

используя стандартный net/http пакет, я могу проверить метод запроса в обработчике func, возможно, так:

func AddResourceHandler(rw http.ResponseWriter, r *http.Request) {
  switch r.Method {
  case "OPTIONS":
    // handle preflight
  case "PUT":
    // respond to actual request
  }
}

Я также могу использовать гориллы mux package и зарегистрируйте обработчик "OPTIONS" для каждого соответствующего URL-адреса.

r := mux.NewRouter()
r.HandleFunc("/someresource/item", AddResourceHandler).Methods("PUT")
r.HandleFunc("/someresource/item", PreflightAddResourceHandler).Methods("OPTIONS")

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

5 ответов


один простой способ отделить вашу логику и повторно использовать обработчик CORS, который вы определяете,-это обернуть обработчик REST. Например, если вы используете net / http и Handle метод вы всегда можете сделать что-то вроде:

func corsHandler(h http.Handler) http.HandlerFunc {
  return func(w http.ResponseWriter, r *http.Request) {
    if (r.Method == "OPTIONS") {
      //handle preflight in here
    } else {
      h.ServeHTTP(w,r)
    }
  }
}

вы можете обернуть такой:

http.Handle("/endpoint/", corsHandler(restHandler))

эта библиотека выглядит многообещающе:

Go CORS handler

CORS-обработчик net / http, реализующий совместное использование ресурсов Cross Origin Спецификация W3 в Golang.


Я лично считаю утомительным добавлять предполетные маршруты для каждого пути, который получит OPTIONS запрос, поэтому вместо этого я просто добавляю свой обработчик в любой OPTIONS метод, который горилла обрабатывает следующим образом:

router.Methods("OPTIONS").HandlerFunc(
    func(w http.ResponseWriter, r *http.Request){
    myHttpLib.OptionsForBrowserPreflight(w, r)
})

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

таким образом, вы можете: (1) иметь только одну регистрацию маршрутизации для всех предварительных рейсов и (2) иметь один обработчик для повторного использования кода и применения логики/правил в одном месте для запросов опций.


горилла/обработчики также имеет хороший обработчик CORS:cors.go

пример использования:

import (
    "net/http"

    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/users", UserEndpoint)
    r.HandleFunc("/projects", ProjectEndpoint)

    // Apply the CORS middleware to our top-level router, with the defaults.
    http.ListenAndServe(":8000", handlers.CORS()(r))
}

вот фрагмент, который работал для меня:

addCorsHeader(res)
if req.Method == "OPTIONS" {
    res.WriteHeader(http.StatusOK)
    return
} else {
    h.APIHandler.ServeHTTP(res, req)
}


func addCorsHeader(res http.ResponseWriter) {
    headers := res.Header()
    headers.Add("Access-Control-Allow-Origin", "*")
    headers.Add("Vary", "Origin")
    headers.Add("Vary", "Access-Control-Request-Method")
    headers.Add("Vary", "Access-Control-Request-Headers")
    headers.Add("Access-Control-Allow-Headers", "Content-Type, Origin, Accept, token")
    headers.Add("Access-Control-Allow-Methods", "GET, POST,OPTIONS")
}