Axios: Interceptors - bagaimana mencegah pesan yang dicegat diselesaikan sebagai kesalahan

Dibuat pada 14 Mar 2016  ·  33Komentar  ·  Sumber: axios/axios

Saya mencoba membuat pencegat untuk 401 tanggapan yang dihasilkan dari token yang kedaluwarsa. Setelah intersepsi saya ingin masuk dan mencoba lagi permintaan dengan token baru. Masalah saya adalah login juga dilakukan secara tidak sinkron, jadi pada saat percobaan ulang terjadi, janji asli ditolak. Apakah ada cara untuk mengatasinya? Berikut kode saya:

axios.interceptors.response.use(undefined, err => {
  if (err.status === 401 && err.config && !err.config.__isRetryRequest) {
    refreshLogin(getRefreshToken(),
      success => {
        setTokens(success.access_token, success.refresh_token)
        err.config.__isRetryRequest = true
        err.config.headers.Authorization = 'Bearer ' + getAccessToken()
        axios(err.config)
      },
      error => { console.log('Refresh login error: ', error) }
    )
  }
})

Komentar yang paling membantu

Anda dapat melakukan sesuatu seperti ini:

axios.interceptors.response.use(function (response) {
  return response;
}, function (error) {

  const originalRequest = error.config;

  if (error.response.status === 401 && !originalRequest._retry) {

    originalRequest._retry = true;

    const refreshToken = window.localStorage.getItem('refreshToken');
    return axios.post('http://localhost:8000/auth/refresh', { refreshToken })
      .then(({data}) => {
        window.localStorage.setItem('token', data.token);
        window.localStorage.setItem('refreshToken', data.refreshToken);
        axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.token;
        originalRequest.headers['Authorization'] = 'Bearer ' + data.token;
        return axios(originalRequest);
      });
  }

  return Promise.reject(error);
});

Semua 33 komentar

Maaf atas keterlambatannya, saya baru melihat masalah ini.

Anda perlu membuat pernyataan pengembalian dari pencegat Anda yang akan membuat Janji tetap hidup. Kurang lebih ubah refreshLogin untuk mengembalikan Janji dan kemudian mengembalikannya dari pencegat Anda.

Atau jika Anda tidak dapat memfaktorkan ulang refreshLogin Anda dapat membungkusnya dengan Promise.

axios.interceptors.response.use(undefined, err => {
  let res = err.response;
  if (res.status === 401 && res.config && !res.config.__isRetryRequest) {
    return new Promise((resolve, reject) => {
      refreshLogin(getRefreshToken(),
        success => {
          setTokens(success.access_token, success.refresh_token)
          err.config.__isRetryRequest = true
          err.config.headers.Authorization = 'Bearer ' + getAccessToken()
          resolve(axios(err.config))
        },
        error => {
          console.log('Refresh login error: ', error)
          reject(error)
        }
      )
    });
  }
})

Tidak, tidak melakukannya.

Baris "let res = err.response" tidak berfungsi - tidak ada respons di err.

Jika saya membiarkannya, maka keberhasilan akan terpicu - jadi login terjadi, tetapi permintaan asli tidak dicoba lagi.

Axios versi apa yang Anda gunakan?

Itu dengan 0.12.0.
Sekarang saya memperbarui ke 0.13.1, err telah menjadi string dengan tumpukan panggilan.

Kesalahan: Permintaan gagal dengan kode status 401
di createError (eval at...

@ dmt0 Apakah Anda berhasil?

@heeton Tidak, sibuk dengan hal lain. Solusi yang diposting tidak "hanya berfungsi". Tapi itu mungkin karena beberapa perilaku lucu di backend saya. Akan membuat Anda tetap diposting...

Anda dapat melakukan sesuatu seperti ini:

axios.interceptors.response.use(function (response) {
  return response;
}, function (error) {

  const originalRequest = error.config;

  if (error.response.status === 401 && !originalRequest._retry) {

    originalRequest._retry = true;

    const refreshToken = window.localStorage.getItem('refreshToken');
    return axios.post('http://localhost:8000/auth/refresh', { refreshToken })
      .then(({data}) => {
        window.localStorage.setItem('token', data.token);
        window.localStorage.setItem('refreshToken', data.refreshToken);
        axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.token;
        originalRequest.headers['Authorization'] = 'Bearer ' + data.token;
        return axios(originalRequest);
      });
  }

  return Promise.reject(error);
});

Di sini, error.response kembali tidak terdefinisi dalam versi 0.14.0.

bolehkah Anda mencoba error.status tolong

axios.interceptors.response.use(undefined, error => {
      console.log(error.status)
      return Promise.reject(error)
    })

Console.log mengembalikan tidak terdefinisi.

Saya cukup yakin seharusnya error.response.status Anda dapat memeriksa objek kesalahan jika memiliki properti tersebut. Saya tidak tahu mengapa itu tidak berhasil di pihak Anda jika Anda hanya memiliki kode sampel terisolasi yang mirip dengan apa yang telah Anda posting di atas.

Apakah masalah ini terselesaikan? Saya menggunakan 0.15.2 dan mengalami masalah aneh ini

@dmt0 Sama dengan Anda... Saya menggunakan 0.15.2 ... Jadi, versi mana yang oke untuk ini?

Saya menggunakan contoh @geocine dari 5 Oktober 2016. Saya menggunakan Vue.js 2.0 solusi saya adalah melihat token untuk perubahan pada Vuex jika berubah maka perbarui apa pun yang berubah. IE jika seseorang ingin menyukai sebuah postingan tetapi JWT telah kedaluwarsa, ia akan memotong permintaan tersebut dan menjalankannya lagi setelah JWT telah di-refresh.

Vue.axios.interceptors.request.use((config) => {
    if (store.state.auth) {
      config.headers.common['Authorization'] = 'Bearer ' + store.state.token
    }
    return config
  }, function (error) {
    // Do something with request error
    return Promise.reject(error)
  })
Vue.axios.interceptors.response.use((response) => {
    return response
  }, function (error) {
    let originalRequest = error.config
    console.log(originalRequest)
    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true
      Vue.axios.post('/users/token', null).then((data) => {
        store.dispatch('authfalse')
        store.dispatch('authtruth', data.data)
        originalRequest.headers['Authorization'] = 'Bearer ' + store.state.token
        return Vue.axios(originalRequest)
      })
    }
    // Do something with response error
    return Promise.reject(error)
  })

apakah ini sudah terpecahkan? tidak ada kesalahan response . itu memberikan tidak terdefinisi. Saya ingin memeriksa apakah statusnya adalah 401 dan kemudian mengarahkan ulang ke login.

Dalam fungsi penolakan pencegat respons, error.response.status dikembalikan dengan benar di versi terbaru (0.15.3).

apakah ini terpecahkan? saya menggunakan versi 0.15.3 tetapi error.response adalah undefined . saya mencoba menangani kesalahan 401.
btw saya menggunakan "Contoh khusus"

Saya dapat mengadaptasi contoh @rlambertsen . Bekerja dengan baik.

Ini juga merupakan masalah bagi saya - v.0.15.3 - kesalahannya hanyalah string kesalahan calltack

ini berfungsi di sini, saya menjalankan axios v0.16.1.

Satu-satunya hal yang perlu diperhatikan adalah jika Anda telah menyetel baseURL dalam konfigurasi Anda, Anda harus menghapusnya dari objek error.config sebelum mencoba kembali permintaan awal.

this.responseInterceptor = this.axios.interceptors.response.use((response) => response, (error) => {
  let value = error.response;

  if (value.status === 401 && value.data.message === 'Expired JWT Token'
    && (!value.config || !value.config.renewToken)) {
    console.log('Token JWT expiré. Reconnexion ...');

    // renewToken performs authentication using username/password saved in sessionStorage/localStorage
    return this.renewToken().then(() => {
      error.config.baseURL = undefined; // baseURL is already present in url
      return this.axios.request(error.config);
    }).then((response) => {
      console.log('Reconnecté !');
      return response;
    });

  } else if (value.status === 401 && value.config && value.config.renewToken) {
    console.log('Echec de la reconnexion !');

    if (error.message) {
      error.message = 'Echec de la reconnexion ! ' + error.message + '.';
    } else {
      error.message = 'Echec de la reconnexion !';
    }

  } else if (value.status === 401) {
    console.log('Accès refusé.');
    // TODO: We could ask for username/password in a modal dialog...
  }

  return Promise.reject(error);
});

Saya mencari solusi selama 3 hingga 4 bulan terakhir tentang ini dan masih tidak ada yang berhasil. Saya menggunakan Laravel untuk mengembalikan kesalahan dan browser dapat mengidentifikasi 401 (Tidak Sah) tetapi tidak membantu dengan axios.
@Toilal Saya mencoba berjam-jam untuk memperbaikinya setiap kali saya melihat komentar yang dapat membantu tetapi tidak berhasil, hari ini saya mencoba lagi dengan "axios": "^0.16.1" tidak berhasil. Dapatkah seseorang tolong bantu dalam hal ini? ada banyak orang yang membutuhkan bantuan dalam hal ini.

Konsol kode di bawah ini Undefined . Sederhana kesalahannya tidak memiliki respons, tidak peduli bagaimana Anda mencoba

axios.interceptors.response.use((response) => response, (error) => {
    let value = error.response
    console.log(value)
})

Bisakah Anda console.log(error) ? Mungkin itu kesalahan internal dan gagal sebelum respons benar-benar dibaca?

Bisakah Anda console.log(error) ? Mungkin itu kesalahan internal dan gagal sebelum respons benar-benar dibaca?

Mungkin Laravel (atau yang lain) mencegat kesalahan sebelum aksioma, dan menolak janji dengan tipe data lain? Saya menggunakan axios di aplikasi VueJS, saat ini aplikasi kecil karena ini adalah proyek baru.

Coba cari tahu apakah Anda memiliki pencegat aksios lain yang berjalan sebelum yang ini?

Ini sebuah string
console.log(kesalahan)

Error: Network Error
    at createError (eval at <anonymous> (app.js:1611), <anonymous>:15:15)
    at XMLHttpRequest.handleError (eval at <anonymous> (app.js:1590), <anonymous>:87:14)

Ini adalah saat saya menghibur error.config
image

Ya, saya menggunakan axios dengan Aplikasi Vuejs, Beginilah cara saya melakukannya

/* global API_URL */
window.axios = require('axios').create({
  baseURL: API_URL,
  timeout: false,
  params: {} // do not remove this, its added to add params later in the config
})

// Add a request interceptor
/* global window axios */
axios.interceptors.request.use(function (config) {
  /* global window Store */
  let token = Store.get('jwt.token')
  let location = Store.get('location')

  // console.log(location.id, location)
  if (token) {
    config.headers.common['Authorization'] = 'Bearer ' + token
  }
  // Append location id for every post/get request
  if (location) {
    if (config.data) {
      config.data.location_id = location.id
    }
    else if (config.params) {
      config.params.location_id = location.id
    }
  }

  return config
}, function (error) {
  // Do something with request error
  return Promise.reject(error)
})

axios.interceptors.response.use((response) => response, (error) => {
    console.log(error.config)
})

@Toilal Saya menemukan masalahnya dan tidak yakin apa yang bisa diperbaiki. Jika saya menghapus
axios.interceptors.request bagian, ini bekerja dengan baik. Haruskah kita menggunakan permintaan dan tanggapan dalam panggilan yang sama? jika ya, apakah Anda tahu pekerjaan di sekitar?

Saya menggunakan keduanya dan berhasil. Apakah Anda mengembalikan objek yang tepat dalam permintaan Anda?
janji pencegat?

Le 11 av. 2017 18:55, "vijay kumar" [email protected] a écrit :

@Toilal https://github.com/Toilal Saya menemukan masalahnya dan tidak
yakin apa yang bisa diperbaiki. Jika saya menghapus
axios.interceptors.request bagian, ini berfungsi dengan baik. Haruskah kita menggunakan keduanya?
permintaan dan tanggapan dalam panggilan yang sama? jika ya, apakah Anda tahu pekerjaan di sekitar?


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/mzabriskie/axios/issues/266#issuecomment-293326920 ,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/ABHJvmxkHSGY0mEXmiygeUW7xViqiiMXks5ru7CGgaJpZM4Hwec2
.

Saya menyelesaikannya, 401 tidak memiliki cors . Jika ada yang menggunakan Laravel dengan Paket Laravel Cors maka inilah solusinya dan Anda akan memiliki error.response tersedia

https://github.com/barryvdh/laravel-cors/issues/89

Saya punya masalah, bahwa error adalah undefined dalam pencegat respons dan itu disebabkan oleh tidak menyelesaikan janji untuk config dalam pencegat permintaan penyegaran token, jika token menyegarkan gagal.

Kode salah dalam pencegat permintaan:

axios.interceptors.request.use(config => this.dispatch('refreshAuthToken').then(() => {
  // do stuff to set Authorization header
  return Promise.resolve(config);
}))

Kode tetap:

axios.interceptors.request.use(config => this.dispatch('refreshAuthToken').then(() => {
  // do stuff to set Authorization header
  return Promise.resolve(config);
// ensure we resolve config in error case
}), () => Promise.resolve(config));

Berdasarkan contoh ini: https://github.com/axios/axios/issues/450#issuecomment -247446276

Saya telah menggunakan versi ini untuk menyegarkan token - seperti yang dijelaskan pada posting di atas. Pencegat ini dibuat untuk mencegah token penyegaran berulang jika dibuat lebih banyak permintaan dan Anda mungkin ingin memanggil operasi ini hanya sekali.

Ini adalah versi TypeScript tapi saya pikir ini sangat mirip dengan versi js.

export default class AuthorizationHelper {

    authTokenRequest: Promise<any>;

    getNewAccessToken() {

        const refreshToken = window.localStorage.getItem("refreshToken");

        if (!this.authTokenRequest) {
            this.authTokenRequest = this.refreshToken(refreshToken);
            this.authTokenRequest.then(response => {
                this.resetGetAccessTokenRequest();
            }).catch(error => {
                this.resetGetAccessTokenRequest();
            });
        }

        return this.authTokenRequest;
    }

    resetGetAccessTokenRequest() {
        this.authTokenRequest = null;
    }

    refreshToken(refreshToken: string): Promise<any> {

        return axios.post('/api/token/refresh',
            {
                refreshToken: refreshToken
            });
    }

    registerAxiosInterceptor() {
        axios.interceptors.response.use((response) => {
            return response;
        }, err => {
            const error = err.response;

            if (error.status === 401 && error.config && !error.config.__isRetryRequest) {

                return this.getNewAccessToken().then(response => {
                    error.config.__isRetryRequest = true;

                    //set new access token after refreshing it
                    axios.defaults.headers.common["Authorization"] = `Bearer ${response.access_token}`;
                    error.config.headers["Authorization"] = `Bearer ${response.access_token}`;

                    return axios(error.config);
                }).catch(error => {

                    //refreshing has failed => redirect to login
                    //clear cookie (with logout action) and return to identityserver to new login
                    //(window as any).location = "/account/logout";

                    return Promise.reject(error);
                });
            }

            return Promise.reject(error);
        });
    }
}
// for multiple requests
let isRefreshing = false;
let failedQueue = [];

const processQueue = (error, token = null) => {
  failedQueue.forEach(prom => {
    if (error) {
      prom.reject(error);
    } else {
      prom.resolve(token);
    }
  })

  failedQueue = [];
}

axios.interceptors.response.use(function (response) {
  return response;
}, function (error) {

  const originalRequest = error.config;

  if (error.response.status === 401 && !originalRequest._retry) {

      if (isRefreshing) {
        return new Promise(function(resolve, reject) {
          failedQueue.push({resolve, reject})
        }).then(token => {
          originalRequest.headers['Authorization'] = 'Bearer ' + token;
          return axios(originalRequest);
        }).catch(err => {
          return Promise.reject(err);
        })
      }

    originalRequest._retry = true;
    isRefreshing = true;

    const refreshToken = window.localStorage.getItem('refreshToken');
    return new Promise(function (resolve, reject) {
       axios.post('http://localhost:8000/auth/refresh', { refreshToken })
        .then(({data}) => {
            window.localStorage.setItem('token', data.token);
            window.localStorage.setItem('refreshToken', data.refreshToken);
            axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.token;
            originalRequest.headers['Authorization'] = 'Bearer ' + data.token;
            processQueue(null, data.token);
            resolve(axios(originalRequest));
        })
        .catch((err) => {
            processQueue(err, null);
            reject(err);
        })
        .then(() => { isRefreshing = false })
    })
  }

  return Promise.reject(error);
});

Proyek demo
Tautan inti

Apa yang Anda lihat di Axios versi 0.13.* kesalahan merespons string yang dikembalikan oleh metode toString dari objek kesalahan.

Di versi yang lebih baru, Jika respons telah diterima dari server, objek kesalahan akan berisi properti respons:
Jadi Anda dapat melakukan sesuatu seperti:

if (error.response) { console.log(error.response.data); console.log(error.response.status); console.log(error.response.headers); }

Apakah halaman ini membantu?
0 / 5 - 0 peringkat