Подтвердить что ты не робот

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

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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

Один простой способ отделить свою логику и повторное использование обработчика 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))

Ответ 2

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

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

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

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

Ответ 3

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

Перейти к обработчику CORS

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

Ответ 4

gorilla/handlers также имеет красивый обработчик 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))
}

Ответ 5

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

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

Ответ 6

Ну, из моего приложения Vue.js ничего не получалось, поэтому я сделал это.

cors := cors.New(cors.Options{
        AllowedOrigins:   []string{"*"}, //viper.GetString("ORIGIN_ALLOWED")
        AllowedHeaders:   []string{"Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token", "Authorization"},
        AllowedMethods:   []string{"GET", "PATCH", "POST", "PUT", "OPTIONS", "DELETE"},
        Debug:            true,
        AllowCredentials: true,
    })

cors.Handler(corsMiddle())
func corsMiddle() http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
        if request.Method == "OPTIONS" {
            w.WriteHeader(http.StatusOK)
        }
    })
}