2
votes

TL;DR

Had some problems with the formatting of my Axios call, and found that using headers as a const or var in my call did not work while dumping headers directly into the call did work.

On the PHP side, there were some extra curly brackets on the Access-Control-Allow-Headers directive that was causing the header response to be bracketed.

All in all it was troubleshooting through the Network tab in Browser Dev tools that helped us find the fix.

I am fairly new to programming in general and new to Vue.js and Axios. So I may be missing pieces conceptually and syntactically. I'm developing a front end to a PHP based application that runs a custom management tool. My goal is to use Vue.js to build out the front end and specifically use Axios to make the API calls.

  • I'm using a Lightsail server with a public port forward.
  • Visual Studio Code with Remote Developer tools installed and connected via SSH to develop on that server rather than my machine.
  • Vue CLI 3 to set up my project and choosing the default packages of Babel and Linting.
  • Axios is installed via npm.

Our PHP environment originally allowed me to pass params like user ID, API Key and a query ( while user = x method=get, apikey=x, ) and I could easily consume the data and output it in a v-for and everything worked pretty well. But, it was not a well designed API structure, so we changed the idea that params would be passed, as I did not like passing the API key in the URL and don't like the idea of having to pass a SQL query to get the data. So, my colleague adjusted the API so now we have a URL that is like https://tunnel.host.com/api/sites/read.php. We'll also have PHP files for the rest of the CRUD operations later. But I need to get past my current problem.

My research immediately led me to the issue of CORS and I've spent many hours reading about that topic and ultimately feel like it is the issue preventing me from passing the necessary headers to the server and getting access.

I thought for a while that installing the CORS npm package would help, but that appears to only be for fixing the issue with a locally hosted server environment. ( like using ExpressJS as the server in a dev environment )

After reading the Mozilla docs regarding CORS I wonder if I need to send preflight headers in an OPTION HTTP request.

So far I have tried: - Adding a vue.config.js file with dev server options ( I'll include the code below ) - Using POSTMAN to construct the headers and pass a GET request - which works just fine - attempting to use the headers key in an Axios object ( code below )

My colleague who runs the PHP side of things assures me that all of the CORS headers in the files are correct.

I only have one component being loaded into App.vue called AxiosTest.

I've edited this post to update my findings.

By sending the headers as const the request is made as GET

const config = {
            headers: {
                    "content-type": "application/vnd.api+json",
                    "Cache-Control": "no-cache",
                    "x-api-key": "9xxxxxxxxxxxxxxxxxxxxxx9"
            }
        }
        axios.get(
            `https://tunnel.xxxxx.com/api/headers.php?`,{ config
            })
            .then(response => {
                this.results = response;
            })
            .catch(error => {
                // eslint-disable-next-line
                console.log(error)
            })

And the header Response

HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Mon, 08 Jul 2019 19:22:55 GMT
Content-Type: application/json; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: http://54.x.x.155:8080
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 0

and the Request

Host: tunnel.xxxxxx.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://54.x.x.155:8080/
Origin: http://54.x.x.155:8080
DNT: 1
Connection: keep-alive
Cache-Control: max-age=0

However, if I keep the headers object inside of the axios.get function I get it sent as OPTIONS

axios.get(
            `https://tunnel.xxxx.com/api/headers.php?`,{
                headers: {
                    "content-type": "application/vnd.api+json",
                    "Cache-Control": "no-cache",
                    "x-api-key": "9xxxxxxxxxxxxxxxxxxxxxx9"
                }
            })
            .then(response => {
                this.results = response;
            })
            .catch(error => {
                // eslint-disable-next-line
                console.log(error)
            })

Response

HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Mon, 08 Jul 2019 19:22:55 GMT
Content-Type: application/json; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: http://54.x.x.155:8080
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 0
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: {cache-control,x-api-key}

Request

Host: tunnel.xxxxx.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: GET
Access-Control-Request-Headers: cache-control,x-api-key
Referer: http://54.x.x.155:8080/
Origin: http://54.x.x.155:8080
DNT: 1
Connection: keep-alive
Cache-Control: max-age=0

vue.config.js

module.exports = {
    devServer: {
        public: '54.x.x.x:8080',
        proxy: 'https://tunnel.xxxxxxx.com/'
    }
  }

In the most successful test produced I still receive Invalid CORS origin or invalid API key.

Any tips, code snippets, links or experience any one can share will be greatly appreciated.

4
If I were trying to debug this I would focus my attention on the Network tab of the browser dev tools. Find the request you're trying to make and carefully study the headers, both on the request and the response. Presumably it's sending an OPTIONS request (automatically generated from your GET request) but does that request have all the headers you would expect? Check the response headers, do they look correct? You haven't included any of that information in the question so it's difficult for me to take this any further. Tunnels/proxies make me wonder if some intermediary is interfering.skirtle
Thank you Skirtle, I have definitely been using the Network tab in the dev tools. Here are headers showing the request and response during a page load or refresh.user3889785
"After reading the Mozilla docs regarding CORS it's clear that I need to send preflight headers in an OPTION HTTP request." — No. The browser will set these automatically.Quentin
Thanks for helping @Quentin, This is all very new to me, so your input is appreciated. I thought because I was sending a Simple Request, ie just a GET request the browser would not send preflight headers. But how would I send my x-api-key header in my Axios request?user3889785
Format your responses as code so they are readable. It's virtually impossible to tell what is going on with all the whitespace tripped. Only include the ones sent and received by Ajax. Include the request and response bodies. Quote error messages associated with them in the Console.Quentin

4 Answers

1
votes

Look at the documentation for axios:

axios.get(url[, config])

The get method takes two arguments but you are passing it three.

Thus the data you are trying to pass is being treated as configuration (and ignored because none of the values are valid config options) and the config data (including the request headers object) is ignored.

The query string needs to be part of the URL. Axios won't use the second argument to generate it for you.

const data = {
    foo: "bar"
};
axios.get(
    `https://example.com/api/headers.php?${new URLSearchParams(data)}`, {
        headers: {
            "Cache-Control": "no-cache",
            "content-type": "application/vnd.api+json",
            "x-api-key": "9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9"
        }
    }).then(response => {
        console.log(response);
    }).catch(error => {
        console.log(error)
    })
0
votes

Had some problems with the formatting of my Axios call, and found that using headers as a const or var in my call did not work while dumping headers directly into the call did work.

On the PHP side, there were some extra curly brackets on the Access-Control-Allow-Headers directive that was causing the header response to be bracketed.

All in all it was troubleshooting through the Network tab in Browser Dev tools that helped us find the fix.

-1
votes

Here is the function that I'm calling at the top of the PHP scripts to allow the requester 100% full CORS access.

function InitCors() {
  if (isset($_SERVER["HTTP_ORIGIN"])) {
    header("Access-Control-Allow-Origin: {$_SERVER["HTTP_ORIGIN"]}");
    header("Access-Control-Allow-Credentials: true");
    header("Access-Control-Max-Age: 0");
  }
  if ($_SERVER["REQUEST_METHOD"] == "OPTIONS") {
    if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"])) header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
    if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"])) header("Access-Control-Allow-Headers: {" . $_SERVER["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"] ."}");
  }
  header("Content-Type: application/json; charset=UTF-8");
}
-1
votes

I also have another test script to echo back all of the $_SERVER array values and I never see any of the custom headers when his Axios calls it. However, if you call things with curl from the command line (adding the headers) they most definitely do appear in the resulting output.

<?
//---------------------------------------------------------------------------------------------------
include("../dashboard/subs.php");
//---------------------------------------------------------------------------------------------------
if (! IS_SSL()) {
  echo("{\"message\":\"API requires all traffic to be SSL encrypted.\"}\n");
  exit;
}
//---------------------------------------------------------------------------------------------------
InitCors();
//---------------------------------------------------------------------------------------------------
  $JSON  = "{\"data\":[";
  $JSON .= json_encode($_SERVER);
  $JSON .= "]}";
  echo("$JSON\n");
//---------------------------------------------------------------------------------------------------
?>