HTTP 헤더 설정


165

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 요청 헤더를 보내는 기술 문서를 가지고?

답변:


227

신경 쓰지 마, 알아 냈어-나는 Set()방법을 사용했다 .Header() .

내 핸들러는 이제 다음과 같습니다.

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

어쩌면 이것은 때때로 나 자신처럼 박탈당한 카페인으로 누군가를 도울 것입니다 :)


2
나는 같은 문제를 겪고 있으며 다음을 추가하는 것이 도움이 될 수도 있습니다. w.Header().Add("Access-Control-Allow-Methods", "PUT") w.Header().Add("Access-Control-Allow-Headers", "Content-Type")
Ray

1
AJAX 클라이언트가 설정하는 경우에는 작동하지 않습니다 withCredentials:true(일반적인 사용 사례 인 신임 정보를 전송할 때 "*"값이 허용되지 않음). 발신자를 요청자에게 설정해야합니다 (방법은 아래 Matt Bucci의 답변 참조).
orcaman

98

위의 모든 답변은 OPTIONS 사전 비행 요청을 처리하지 못하기 때문에 잘못되었습니다. 해결책은 mux 라우터의 인터페이스를 재정의하는 것입니다. 커스텀 헤더로 실패한 AngularJS $ http get 요청을 참조하십시오 (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)
}

19
"위의 모든 것"… 답변은 여러 가지 방법으로 정렬 될 수 있으므로이 구가 원하는 것을 의미하지는 않습니다.
Dave C

간단한 CORS 요청에는 프리 플라이트가 없으며 모두 서비스하려는 대상에 따라 다릅니다.
laike9m

Access-Control-Allow-Credentials": "true"httpOnly 쿠키가있는 요청을 잊지 마십시오 .
Federico

23

완전히 공개적인 행동이 필요할 때까지 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 요청에이 헤더를 모두 회신하는 것을 잊지 마십시오.


1
이 래퍼의 사용법을 잘 이해하지 못합니다.이 코드로 http 핸들을 래핑하는 방법의 예를 들어 줄 수 있습니까? 저는 현재 고릴라 mux를 사용하고 있습니다. router.HandleFunc("/user/action", user.UserAction) http.Handle("/", router) http.ListenAndServe(":8080", nil).Set("Access-Control-Allow-Origin", "*")
Matt Bucci

2
이제 router.HandleFunc("/user/action", addDefaultHeaders(user.UserAction)) 약 16 개의 라우트가 있기 때문에 addDefaultHeaders로 핸들 호출을 래핑하고 있습니다. 이것은 http 패키지 또는 mux 라우터 계층에서 래퍼로 지정할 수있는 방법이 이상적이지 않습니다.
Matt Bucci

14

적절한 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)
        })
    }
}

엔드 포인트

기억하세요! 미들웨어가 역순으로 적용됩니다 (ExpectGET ()이 먼저 실행 됨)

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

14

라우터를 재정의하지 않으려는 경우 경우 (이를 지원하는 방식으로 앱을 구성하지 않았거나 경로별로 경로에 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)에 대해서만 "*"를 수행 할 수 있다고 생각하지만 다른 경우에는 위에서처럼 원점을 명시 적으로 설정해야합니다.


12

이 경우 래퍼를 만듭니다.

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

1

위에서 설명한 것과 동일한 문제가 발생했습니다. 위의 솔루션이 정확합니다. 설정은 다음과 같습니다 .1) 클라이언트의 Angularjs 2) GO 서버의 Beego 프레임 워크

다음 사항을 준수하십시오. 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 또는 요청 유형을 변환합니다.


-7

나는 이것이 대답에 다른 변형이라는 것을 알고 있지만 웹 서버에 더 관심이 아닌가? 예를 들어 nginx 가 도움이 될 수 있습니다.

ngx_http_headers_module 모듈있게 응답 헤더의 "만료"및 "캐시 제어"헤더 필드에, 임의의 필드를 추가

...

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

프로덕션 환경에서 go 서비스 앞에 nginx 를 추가하는 것이 현명합니다. 요청을 승인, 로깅 및 수정하기위한 훨씬 더 많은 기능을 제공합니다. 또한 서비스에 액세스 할 수있는 사람을 제어 할 수있는 기능을 제공 할뿐 아니라 위에서 설명한 것처럼 앱의 특정 위치에 대해 다른 동작을 지정할 수 있습니다.

go api와 함께 웹 서버를 사용하는 이유에 대해 계속할 수 있지만 다른 토론의 주제라고 생각합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.