1

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!

4
  • Full code can be access on Github github.com/abhimanyu1990/go-connect Commented Oct 14, 2020 at 5:34
  • Do you use an incognito window? So the browser didn't cache an old version of your site? Commented Oct 14, 2020 at 7:53
  • No I haven't used the incognito mode. As I have restarted swagger multiple time and each time it start on new port Commented Oct 14, 2020 at 8:53
  • Did you end up resolving the issue above? If so, can you please share insights into how? Commented Nov 17, 2020 at 19:40

2 Answers 2

1

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")
Sign up to request clarification or add additional context in comments.

3 Comments

I have already tried this but it doesn't make any difference.
I think it solves 405 method not allowed issue. I tested this on my side, it works
Yes, cloned your repo & tested well locally
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.