Why axios requests will be cached after deployment? I've deploy my nuxt.js project with command nuxt generate and when share my project to shared hosting and refresh the page then post updates or new comments to post not showed. I make axios request inside asyncData method.
Code:
import axios from 'axios'
export default {
async asyncData({ req, params }) {
let [post, comments] = await Promise.all([
axios.get(`/post/${id}`),
axios.get(`/post/${id}/comments`),
])
return {
post: post.data,
comments: comments.data
}
}
}
How I can make axios request which not will be cached generaly in Nuxt.js?
Related
I'm trying to fetch the latest Instagram posts from a feed using Vue 3 and Axios. Instagram has introduced a strict-origin-when-cross-origin policy, so I keep getting blocked. Access tokens and everything is already set up.
Using the guide for Instagram Basic Display API isn't exactly helpful, big surprise there.
main.js
import { createApp } from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
import App from './App.vue'
const app = createApp(App)
app.use(BootstrapVue3, VueAxios, axios)
app.provide('axios', app.config.globalProperties.axios)
app.mount('#app')
App.vue
<template>
<Home />
</template>
<script>
import { inject } from 'vue'
import Home from './components/Home.vue'
export default {
name: 'App',
components: { Home },
setup() {
inject('axios')
}
}
</script>
Home.vue
export default {
name: 'Home',
mounted() {
axios.get('https://api.instagram.com/me?fields=id&access_token=myToken')
.then(response => {
console.dir(response)
}).catch(err => {
console.error(err)
})
}
}
</script>
Access to XMLHttpRequest at 'https://api.instagram.com/me?access_token={myToken}'
from origin 'http://localhost:1234' has been blocked by CORS policy: No 'Access-Control-Allow-Origin'
header is present on the requested resource.
CORS Header Proxy or cors-anywhere would be helpful of course, but I want to do this properly... and I don't know how to implement CORS Header Proxy in Vue :)
What you are trying to achieve is not possible as-is, and if it were, it would be considered a browser bug. CORS is meant to restrict resources that the browser will load via XMLHttpRequest (XHR).
You have two choices:
Proxy the request
As #Phil mentioned in their comment, you will need to proxy the request through some backend where CORS is ignored. Thus, the backend can make the request, fetch the results and return the results to your Vue app. The backend logic should be very simple and you can use axios there as well.
Note: This can be unsafe as you will need to forward the access token of the user to the backend.
Write a browser extension that adds in the access-control-allow-origin header
A browser extension has the ability to modify request and response headers. Writing an extension to do this is quite straightforward as well. You need a background script with content similar to this:
browser.webRequest.onHeadersReceived.addListener((e) => {
const { tabId, responseHeaders } = e
// Add logic to ensure that the header modification only happens on _your_ requests
responseHeaders.push({
name: 'access-control-allow-origin',
value: '<your domain>' // You can throw in '*', which is not a valid value but browsers ignore this error
})
return { responseHeaders }
},
{ urls: ['https://api.instagram.com/*'] },
['blocking', 'responseHeaders'])
I want to call an API in asyncData()
async asyncData({ $axios, params, store }) {
let itemUUID = params.item;
let item = await $axios.get("/item/" + itemUUID);
return {item};
}
Problem: Axios is still making the request on http://localhost:3000
if I do a console.log($axios.defaults.baseURL) the correct baseURL of my API is printed.
This also works if I use my store action & make the call by using this.$axios
I am using #nuxtjs/axios 5.13.1 with Nuxt 2.15.6 in SSR mode and configured it with the correct baseURL in the nuxt.config.js
Interestingly, if I edit my page content and a hot module reload is triggered, the correct URL is used. Maybe the question should be if Axios is triggered in the right time, on the server?
Edit: I checked the request that was made on HMR and this was triggered in the client.js.
If I call my store inside the created() hook the request gets executed successfully.
My nuxt.config.js:
publicRuntimeConfig: {
axios: {
baseURL: process.env.EXPRESS_SERVER_URL
}
},
privateRuntimeConfig: {
axios: {
baseURL: process.env.EXPRESS_SERVER_URL,
}
},
I'm not sure what is the NODE_TLS_REJECT_UNAUTHORIZED=0 thing doing but your frontend configuration (Nuxt) is working well so far.
Sorry if I cannot help on the Express part.
Maybe try to setup HTTPS locally on Nuxt: How to run NUXT (npm run dev) with HTTPS in localhost?
TLDR; This was not related at all - I forgot to set the auth token for my backend. At the time of axios init it's not present. $axios object doesn't have auth - backend fails.
On page load the nuxt function nuxtServerInit() is used to get the auth token out of the acces_token cookie.
I am using a plugin to initialize Axios - with the token from the store.
But of couse the token is not present at the time axios is initialized as nuxtServerInit is called after plugin init.
In my axios.js plugin I changed:
export default function({ app, error: nuxtError, store }) {
const token = const token = store.state.user.token;
app.$axios.setToken(token, "Bearer");
}
to;
export default function({ app, error: nuxtError, store }) {
const token = app.$cookies.get("access_token");
app.$axios.setToken(token, "Bearer");
}
Now the token is present & used for every request happening server-side.
What I'm trying to do is to create an Axios instance in my nuxt app and modify the baseURl to be the same as the domain but with some prefixes and import this instance from an external js file.
for example, I tried to interceptors the request and modify the domain but in the normal Axios package there is no referer to the current domain in '#nuxt/axios' module there is the referer of the current domain but only if I use the module:
axiosInstance.js:
import axios from 'axios';
// Note I don't want to use baseURL to be static.
const api = axios.craete();
api.interceptors.request.use( (config) => {
const prefixedDomain = prefixDomian(config.headers.common.refere)
config['baseURL'] = prefixedDomain
return config;
}, (error)=> {
return Promise.reject(error);
});
export default api
test.js:
import api from 'axiosService';
const settings = async () => {
const setting = await api.get('/settings');
return settings
}
export default settings
but this code doesn't work because the header is empty inside the config.
The only result that I want is to create an Axios instance with the baseURL prefixed and can import it and use it in an external file.
So firstly i create custom axios instance with baseurl and export it like this:
import axios from 'axios';
const instance = axios.create({
baseURL: process.env.BACKEND_URL,
});
instance.defaults.headers.common['Authorization'] = 'AUTH TOKEN';
instance.defaults.headers.post['Content-Type'] = 'application/json';
export default instance;
The problem is in my saga or in any component in general (ONLY client side) when importing this custom axios instance. I use next-redux-wrapper, and when i prefetch data (using getStaticProps) for my component everything works fine and the axios.defaults.baseURL property works just fine.
However the problem is on client-side, whenever i import the same axios instance in any component or in saga but i call it from lets say componentDidMount, the same axios.default.baseURL is undefined, so if i want to make get request i have to type in the full backend + queries URL. What could the problem be? EXAMPLE:
export function* fetchTPsSaga() {
try {
console.log(axios.defaults.baseURL);
const url = `/training-programs`;
const res = yield axios.get(url);
const tPs = res.data.data;
yield put(fetchTrainingProgramsSuccess(tPs));
} catch (err) {
yield put(fetchTrainingProgramsFail(err));
}
}
// The first time it renders (on server side), it's the valid baseURL property, however if i call the same saga from client-side (when component is rendered) it's UNDEFINED, so i have to type the full url
process.env only work on server-side. You can use publicRuntimeConfig to access environment variables both on client and server-side.
next.config.js
module.exports = {
publicRuntimeConfig: {
// Will be available on both server and client
backendUrl: process.env.BACKEND_URL,
},
}
axios instance file
import axios from 'axios';
import getConfig from 'next/config';
const { publicRuntimeConfig } = getConfig();
const instance = axios.create({
baseURL: publicRuntimeConfig.backendUrl,
});
By the way, if you are using Next.js versions 9.4 and up, the Environment Variables provide another way.
Loading Environment Variables Rules
In order to expose a variable to the browser you have to prefix the variable with
NEXT_PUBLIC_
. For example:
NEXT_PUBLIC_BACKEND_URL='http://localhost:3000'
Then you can access this env variable in Axios as its client-side rendering
import axios from 'axios';
const instance = axios.create({
baseURL: process.env.NEXT_PUBLIC_BACKEND_URL,
});
*Note: You have to use process.env.NEXT_PUBLIC_BACKEND_URL instead of process.env.BACKEND_URL
I'm practicing NUXT and from tutorial its working well. mine fail when entering the NUXT middleware. the logic is if page is redirecting to other page it will enter middleware and fetch the result using axios.
middleware/search.js
import axios from 'axios';
export default function ({ params, store }) {
console.log(store)
return axios.get(`https://itunes.apple.com/search?term=~${params.id}&entity=album`)
.then((response) => {
console.log(response.data.results);
store.commit('add', response.data.results)
})
}
when entering here the store.commit('add'... will result
Cannot read property 'commit' of undefined
when I echo commit = undefined.
What I'm missing? I already tried this.$store.commit(...) still undefined.
VUEX
store/index.js
import Vuex from 'vuex'
const createStore = () => {
return new Vuex.Store({
state: {
albums: []
},
mutations: {
add (state, payload) {
state.albums = payload
}
}
})
}
export default createStore
I found a solution from the comments of the said tutorial but I want to share here if others struggle it too.
halt your development server ctrl+C
then restart the your dev server
npm run dev
then VUEX will be seen now in the middleware tnx
Restarting the Dev Server worked for me as well. It seems Vuex isn't reloaded when changes are made.
Run npm run dev and it should work.