1
votes

I'm using VueJS for an app I am building. The server I have is written in Golang and has been set to accept CORS. In the app, in one of my components, searchBar, I have set it to fetch some data before it is created.

var searchBar = {
    prop: [...],
    data: function() {
        return { ... };
    },
    beforeCreate: function() {
        var searchBar = this;

        axios.request({
            url: '/graphql',
            method: 'post',
            data: {
                'query': '{courses{id, name}}'
            }
        })
        .then(function(response) {
            searchBar.courses = response.data.data.courses;
        });
    },
    methods: { ... },
    template: `...`
};

Axios works perfectly here. It gets the data I need. searchBar has a button which causes it to emit an event which is then picked up by another component, searchResults. Upon receiving the event, searchResults will fetch some data.

var searchResults = {
    data: function() {
        return { ... }
    },
    mounted: function() {
        var sr = this;

        this.$bus.$on('poll-server', function(payload) {
            var requestData = {
                url: '/graphql',
                method: 'post',
                data: { ... },
                ...
            };
            ...

            axios.request(requestData)
                 .then(function(response) {
                     console.log(response);
                 }
            );
        });
    },
    template: `...`
};

Note that my Axios request call is now inside a callback function. When this call is performed, I receive a CORS error:

Access to XMLHttpRequest at 'http://127.0.0.1:9000/graphql' from origin 'http://127.0.0.1:8080' 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.

My server is located at http://127.0.0.1:9000, with the client in http://127.0.0.1:8080. Here is the content of the OPTIONS request of the second request call.

Second call's OPTIONS method request headers.

For comparison, here is the request header of the first request call (that works!).

First call's OPTIONS method request headers.

I have already set my Golang server to support CORS via go-chi/cors. This is how set it up.

router := chi.NewRouter()
...    
// Enable CORS.
cors := cors.New(cors.Options{
    AllowedOrigins:   []string{"*"},
    AllowedMethods:   []string{"POST", "OPTIONS"},
    AllowedHeaders:   []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
    ExposedHeaders:   []string{"Link"},
    AllowCredentials: true,
    MaxAge:           300,
})

router.Use(
    render.SetContentType(render.ContentTypeJSON),
    middleware.Logger,
    middleware.DefaultCompress,
    middleware.StripSlashes,
    middleware.Recoverer,
    cors.Handler,
)

router.Post("/graphql", gqlServer.GraphQL())

return router, db

What is causing the error I am having and how can it be solved?

2
Not familiar with go-chi/cors, but are you sure CORS is set up correctly? You most likely have it correct for your first POST request, but not for the second GET request. The error clearly shows no Allowed Origin header on the 2nd API.colm.anseo
@colminator I accidentally left the details for the second request. The second request is also a POST request.Sean Francis N. Ballais
Please check the OPTIONS request that is being sent to the server and the response and, if you could, post them hereBen Yaakobi
@BenYaakobi, I have added the OPTIONS request to the question.Sean Francis N. Ballais
@RejoanulAlam, yes, for local test no security is required. But, it is much preferable to match the dev/local with what would be in production.Sean Francis N. Ballais

2 Answers

2
votes

This CORS error is expected. The CORS plugin you are using does request filtering for you. If you look at the list of allowed headers, you can see it's missing the header called snb-user-gps-location that you are trying to send in your axios call.

Either add that header to the allowed list, or don't send it from the front end.

2
votes

I still suspect the go-chi CORS setup. I would suggest looking at setting up CORS by hand. It's not that difficult. This page will get a basic setup: https://flaviocopes.com/golang-enable-cors/

If that works with your nested API setup, we can then work backwards to determine the go-chi config issue.


Update:

I would also investigate the other middleware steps - commenting out all non-essential ones.

Middleware handlers normally inspect the r *http.Request or write headers to the w http.ResponseWriter and then the final handler will write to the response body. But throughout the middleware chain the following header/body write flow should look like one of these two flows:

Success:

w.Header().Set(...) // headers
w.Write(...) // body

Note the above flow will issue an implicit http status code write, to keep headers appearing first and body second:

w.Header().Set(...) // headers
w.WriteHeader(http.StatusOK) // implicit success http status code
w.Write(...) // body

Failure:

In the event of reporting a runtime error, the flow should be:

w.Header().Set(...) // headers
w.WriteHeader(http.StatusInternalServerError) // some unrecoverable error 
w.Write(...) // optional body

The reason I bring this up, I've seen 3 types of bugs which mess up this flow:

  • bad middleware handlers write headers after the body causing client confusion
  • calling http.Error thinking that stops the API dead - instead of returning immediately after the http.Error and ensuring no subsequent middleware handlers are called
  • write the same header twice. Rewriting headers in a subsequent handler will cause the client to see the last version (thus clobbering any previous versions)

So to fully trace things, I would log.Println all header/body writes for your API to ensure the above flow is correct and no intended values are being overwritten.