axios-module icon indicating copy to clipboard operation
axios-module copied to clipboard

asyncData + extending axios

Open shaneheyworth opened this issue 6 years ago • 13 comments

Hey there,

Awesome job.

I may be just an idiot but I've spent the better part of 12 hours on this now.

Code is working great when used in methods, etc. But when I use it in asyncData, console informs me that the extension is working but it isn't adding the header I set. Please note: it does add the header I set in this with methods, but not in app via asyncData.

Here's some of my code

axios.js `export default function ({ $axios, redirect }) { $axios.onRequest(config => {

$axios.setHeader('test', 'DmiGiYKxwYJ1jMfH9gtFBPgLzmwDS0HPWiM3wuugzUUqlA4Z6PbN8pnYRpEmeU4FRslHbY7M91YF1c3QGTCmo7J2oHTseE0mbe8Z')
// console.log($axios.defaults)
console.log(config)
console.log('Making request to ' + config.url + ' and adding api')

})`

asyncData in main vue page `async asyncData ({ app, params, store }) { console.log('app', app)

    const events = await app.$axios.$get('/events/finder?search='+store.state.frontState.search+'&distance='+store.state.frontState.distance+'&type='+store.state.frontState.type, {
                headers: {
                    latitude: store.state.location.lat,
                    longitude: store.state.location.lon
                }
            })

    // console.log('events',events)

    return { events }`

The only header not passing through is the one set through extending. It works when through method but when calling via app.$ it's not working. I can pass through the header manually in asyncData and the code works. But through the extended axios area it's not setting it, but is firing the 'Making request to' console.log

This question is available on Nuxt.js community (#c110)

shaneheyworth avatar Mar 26 '18 19:03 shaneheyworth

I'm having this issue as well, the axios plugin isn't setting the headers before the asyncData req is sent (perhaps a race condition?). I've noticed this only happens when I navigate to that page, when I go to the url directly the plugin works as expected.

sschadwick avatar Apr 11 '18 16:04 sschadwick

Hey sschadwick, I got around this by changing how I set the headers beforehand:

Rather than using the out of the box .setHeader that they encourage, I simply took the config that gets passed into the plugin and manually set it like any variable. So instead of:

` export default function ({ $axios, redirect }) { $axios.onRequest(config => {

$axios.setHeader('test', 'DmiGiYKxwYJ1jMfH9gtFBPgLzmwDS0HPWiM3wuugzUUqlA4Z6PbN8pnYRpEmeU4FRslHbY7M91YF1c3QGTCmo7J2oHTseE0mbe8Z')`

I did

` export default function ({ $axios, redirect }) { $axios.onRequest(config => {

config.headers.test = 'DmiGiYKxwYJ1jMfH9gtFBPgLzmwDS0HPWiM3wuugzUUqlA4Z6PbN8pnYRpEmeU4FRslHbY7M91YF1c3QGTCmo7J2oHTseE0mbe8Z' 

`

Works fine now and is stable, but is not the way the docs laid everything out. I think setHeader gets re-written by the headers in the actual call, vs my method simply adds it to the default config that gets pulled prior to call

shaneheyworth avatar Apr 11 '18 18:04 shaneheyworth

Glad you got it to work! I noticed that my plugin was attaching the token to axios defaults AFTER the asyncData request was sent. Here's what I did to solve the issue. This way sets the token once, so you don't have to worry about race conditions for each $axios.onRequest.

// nuxt.config.js
// mount plugin under `auth.plugins` instead of `plugins` for plugin access to $auth
auth: {plugins: [{src: '~/plugins/axios.js', ssr: true}]}
// ~/plugins/axios.js
export default ctx => {
  let token = ctx.app.$auth.getToken('shibboleth');
  ctx.app.$axios.setHeader('Authorization', token);
}

sschadwick avatar Apr 11 '18 21:04 sschadwick

Hi,

Please help me,

on my ~/plugins/axios

import Cookie from 'js-cookie';


export default function ({ $axios, redirect }) {
    let __token = Cookie.get("token");

    $axios.defaults.headers.common.Authorize = __token;

    $axios.onRequest(config => {
        console.log($axios);
        console.log('Making request to ' + config.url)
    })
  
    $axios.onError(error => {
        const code = parseInt(error.response && error.response.status)
        const data = error.response.data;
        

    
            if (code === 400) {
                redirect('/400')
            }
       
    })


  }

the I have an action from my module ~/store/module/login/actions

....
function  verifyCode ({app, commit}, data) {
    let post =  querystring.stringify(data);

    return  this.$axios.$post('/login/otp', post)
                    .then(
                        data => {
                            Cookie.set('token', data.data.user.token);
                            Cookie.set('uid', data.data.user.userid);
                            
                            commit('SET_AUTH',{
                                token : data.data.user.token,
                                id    : data.data.user.userid
                            });

                            // dispatch user information from profile
                            console.log(this.$store)
                            this.dispatch('profile/getUserDetails',{},{root: true});
                        }
                    );
}
....

but on execution of getUserDetails, It didn't get the token from the Cookie. But on refresh it's working

gomezmark avatar Apr 26 '18 12:04 gomezmark

Can reproduce this as well

manniL avatar Sep 08 '18 23:09 manniL

I think the axios module doesn't respect the setting in plugins settings when called from server. I set up the axios to use https, but whenever there is an asyncData call, it goes to http instead of https. But if it is used on the client side, everything works fine.

WangHansen avatar Oct 30 '18 13:10 WangHansen

Reproduction repo of @WangHansen https://codesandbox.io/s/m3z9y99mrj

manniL avatar Oct 30 '18 23:10 manniL

Any update for this? I am experiencing #171 and #174 as well which should be related to this issue.

evshiron avatar Apr 10 '19 12:04 evshiron

+1

s01c83l20 avatar Jun 11 '19 10:06 s01c83l20

I've just come across a similar issue when using Nuxt in SPA mode...

If I attempt to set the Authorization header within the onRequest hook, the first call to my API will fail because the token wasn't sent. When making a second call to the API all is fine and the auth header is present.

export default ({ $axios, store }) => {
  $axios.onRequest((config) => {
    $axios.setToken(store.state.oidc.access_token, 'Bearer')
  })
}

Upon finding this post I changed my plugin to set the header directly as follows and my first call to the API receives my auth token and life is good...

export default ({ $axios, store }) => {
  $axios.onRequest((config) => {
    config.headers.Authorization = 'Bearer ' + store.state.oidc.access_token
  })
}

DuelMonster avatar Jul 17 '19 15:07 DuelMonster

This is not a bug but a misuse of users.

Use $axios.setToken or $axios.setHeader in onRequest is not good practice and can cause a lot of problems, because it is changing the default value of the next requests and not the current one

@pi0 should we put a notice on docs?

ricardogobbosouza avatar Oct 22 '19 11:10 ricardogobbosouza

@ricardogobbosouza YES sure. For http module (http.nuxtjs.org) it should be documented too.

pi0 avatar Oct 22 '19 12:10 pi0

I am having quite the similar issue but in the Nuxt middleware when using the store.dispatch(), where my Vuex actions contain this.$axios.$get().

middleware/auth.js:

export default async function(context) {
  if (process.server) {
    const { req, redirect, store } = context;
    if (!req.user) {
      redirect('/login');
    } else {
      const user = req.user;
      await store.commit('auth/received_user', {
        id: user.id,
        email: user.email
      });
      store.dispatch('subscriptions/fetchUserSubscriptionStatus');
    }
  } else if (process.client) {
    const { store, redirect } = context;
    if (!store.getters['auth/isLoggedIn']) {
      redirect('/login');
    }
  } else {
    throw new Error('Failed middleware');
  }
}

As you look at the above code, I can call store.commit without any problem, once I added the store.dispatch inside middleware, it didn't run the action at all. The action works fine when I place it inside mounted().

My Vuex action:

async fetchUserSubscriptionStatus({ commit, state }) {
    try {
      const currentPlan = await this.$axios.$get('/subscription/userPlan');
      commit('setPlan', currentPlan);
    } catch (err) {
     // Handle error
    }
  },

fevernova90 avatar Apr 07 '20 16:04 fevernova90