简体   繁体   中英

CORS Issue in Golang while accessing API from go-swagger UI

I have implemented go-swagger for my API documentation which is running on a different port on my localhost and my application is running on the port 8888. I have implemented cors https://github.com/rs/cors

my code for implementing cors is

var Router = func() *mux.Router{
    router := mux.NewRouter()
    var c = cors.New(cors.Options{
        AllowedOrigins: []string{"*"},
        AllowCredentials: true,
        AllowedMethods :[]string{"POST", "PUT","GET","DELETE","OPTIONS"},
        AllowedHeaders:   []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
        MaxAge: 300,
        // Enable Debugging for testing, consider disabling in production
        Debug: true,
    })


    RegisterHandler := http.HandlerFunc(controllers.Register)
    router.Handle("/api/register",c.Handler(middleware.RequestValidator(RegisterHandler,reflect.TypeOf(dto.UserRequest{})))).Methods("POST")
    fmt.Println("var1 = ", reflect.TypeOf(router)) 
    return router
}

When hitting the request from Postman it seems the code is running fine

Postman Response Header

access-control-allow-credentials →true
access-control-allow-origin →*
content-length →123
content-type →application/json
date →Wed, 14 Oct 2020 04:02:37 GMT
vary →Origin 

As I have enabled debug while implementing cors middleware log printed on my console is as follows

Console log

[cors] 2020/10/14 09:32:37 Handler: Actual request
[cors] 2020/10/14 09:32:37   Actual response added headers: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Origin:[*] Vary:[Origin]]

Issue

When I accessing the same API from Swagger-UI in the browser I am getting cors issue that the "Access-Control-Allow-Origin" header is not set

Access to fetch at 'http://localhost:8888/api/register' from origin 'http://localhost:45601' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

And there is no log printed on the console.

It seems while accessing the API from Swagger UI, cors middleware code is not accessible.

Here is the bowser network call detail of the response for swagger

HTTP METHOD = OPTIONS

General

Request URL: http://localhost:8888/api/register
Request Method: OPTIONS
Status Code: 405 Method Not Allowed
Remote Address: [::1]:8888
Referrer Policy: strict-origin-when-cross-origin

Response Header

Content-Length: 0
Date: Wed, 14 Oct 2020 04:25:23 GMT

Request Header

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en-IN;q=0.9,en;q=0.8
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:8888
Origin: http://localhost:45601
Pragma: no-cache
Referer: http://localhost:45601/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36

Fetch

General

Request URL: http://localhost:8888/api/register
Referrer Policy: strict-origin-when-cross-origin

Request Header

Provisional headers are shown
accept: application/json
Content-Type: application/json
Referer: http://localhost:45601/
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36

Thank you!

You need to allow OPTIONS method on the router.

https://github.com/abhimanyu1990/go-connect/blob/main/app/conf/router.configuration.go#L30

router.Handle("/api/register", c.Handler(middleware.RequestValidator(RegisterHandler, reflect.TypeOf(dto.UserRequest{})))).Methods("POST", "OPTIONS")

This is annoying when I work to try to enable CORS and write header in Go. Finally, I create a struct wrapping ResponseWriter to detect header is already written or not and it work fine.

package router

import (
    "log"
    "net/http"
)

const (
    noWritten     = -1
    defaultStatus = http.StatusOK
)

type ResponseWriter struct {
    writer http.ResponseWriter
    size   int
    status int
}

func (w *ResponseWriter) Writer() http.ResponseWriter {
    return w.writer
}

func (w *ResponseWriter) WriteHeader(code int) {
    if code > 0 && w.status != code {
        if w.Written() {
            log.Printf("[WARNING] Headers were already written. Wanted to override status code %d with %d", w.status, code)
        }
        w.status = code
    }
}

func (w *ResponseWriter) WriteHeaderNow() {
    if !w.Written() {
        w.size = 0
        w.writer.WriteHeader(w.status)
    }
}

func (w *ResponseWriter) Write(data []byte) (n int, err error) {
    w.WriteHeaderNow()
    n, err = w.writer.Write(data)
    w.size += n
    return
}

func (w *ResponseWriter) Status() int {
    return w.status
}

func (w *ResponseWriter) Size() int {
    return w.size
}

func (w *ResponseWriter) Written() bool {
    return w.size != noWritten
}

And in the response:

func respondJSON(w *router.ResponseWriter, status int, payload interface{}) {
    res, err := json.Marshal(payload)
    if err != nil {
        respondError(w, internalErrorStatus.number, internalErrorStatus.description)
        return
    }

    go w.WriteHeader(status)
    header := w.Writer().Header()
    header.Add("Access-Control-Allow-Origin", "*")
    header.Add("Content-Type", "application/json")
    header.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
    header.Add("Access-Control-Allow-Headers", "*")

    w.Write([]byte(res))
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM