So we have this strange issue on our Nuxt 2 front end which is running on a server in Azure app service. The back end is Java spring also running on Azure app service. So what happens is that anytime the app redirects to another link, or you refresh the page, or you open link in a new tab, it adds a trailing slash to the link. For most pages, this doesn't seem to be an issue. However, we made an update to a page, to remove an old embedded form and instead have a link to a new page with the form on it. The issue becomes apparent when you try to login on the updated page. It logs you in, then redirects to the last page you were on. But it adds a trailing slash. So /SomePage becomes /SomePage/. When you refresh the page, the same thing happens. Also should note we wanted a similar url structure for the new page, so we made a dynamic route page out of the old page. So made a directory called SomePage, then added the page as _SomePage.vue and the new form page as Form.vue. So the link to the new form page would be /SomePage/Form.
It seems like when this trailing slash appears, then the page does not function as expected. When on this trailing slash version of the page, the page loads, but it's like it's loading an older version of the page. Like for the page I mentioned above, it should no longer have an embedded form, but when I'm on /SomePage/ the embedded form still appears. Tried messing with the routing and setting up the pages to have their own unique routes. So instead of /SomePage/Form, it would be /Form. But the same issue still happened. So it brought it back to the old setup of /SomePage/Form. After doing this, /SomePage now tries to link to that /Form page but it now looks like /Form/. So I removed that page, and it should no longer exist under that route, but it's like it's looking at older version of the pages or something. The trailing slash only seems to appear on the Azure app service server. When running locally, it does not appear.
I tried adding into my Nuxt.config.js
trailingSlash: false
This didn't help and just caused more issues. Now the trailing slash still appears but causes error on any of those pages. Tried adding a redirect, this works for now and redirects away from /SomePage/ to /SomePage/Form but I know on our test server it got messed up after too many updates and stopped working. Tried adding a web.config file to add rules to remove slash but this didn't seem to work. Not sure what to try next, and not really sure what the cause of the issue could be. Is the issue with Nuxt, or is it with the Azure app service?
So it seems the fix would be either to remove this trailing slash so it doesn't appear at the end of links anymore. Or to remove these older cached versions of pages that seem to appear only when you are on one of those trailing Slash pages. I'll add any code or configs if that would help figure this issue out. Just need to know what to look at.
Here is the SomePage.vue
export default {
name: 'SomePage',
layout: 'about',
mixins: [global],
//middleware: 'trailingslash',
components: {
},
data() {
return {
metaDescription: null,
metaKeywords: null,
backupDescription: 'backup',
backupKeywords: 'Backup',
toggle: false,
showInfo: true,
loading: false,
userId: '',
productId: '',
productName: '',
existingSubscriptionId: '',
startDate: '',
endDate: '',
active: false,
institution: '',
firstName: '',
lastName: '',
canRenew: false,
subscriptionCost: 0.0,
renewal: false
};
},
head() {
return {
title: 'SomePage',
meta: [
{
hid: 'somePage',
name: 'somePage',
content: 'somePage'
},
{
name: 'description',
hid: 'description-advantage',
content: (this.metaDescription != null) ? this.metaDescription : this.backupDescription,
},
{
name: 'keywords',
hid: 'keywords-advantage',
content: (this.metaKeywords != null) ? this.metaKeywords : this.backupKeywords,
}
]
}
},
mounted() {
if (process.browser) {
this.$gtag('config', process.env.GOOGLE_STREAM_ID, {
page_title: this.$metaInfo.title,
page_path: this.$route.fullPath,
})
}
this.getSubscribeToFormPage();
},
created () {
this.getMetaKeywordsAndDescription();
this.loading = true;
if (this.$route.params.subscribe) {
this.toggle = true;
}
},
methods: {
getMetaKeywordsAndDescription() {
return new Promise((resolve, reject) => {
ConnectionContentService.getSectionKeywordsAndDescriptionByContentType(23, 24)
.then((response) => {
if (response) {
this.metaKeywords = response.keywords;
this.metaDescription = response.description;
}
})
.catch((error) => {
console.log(error);
});
});
},
viewSampleDocs() {
this.$store.commit('data/setSampledocsCountryFilter', null);
this.$store.commit('data/setSampledocsCategoryFilter', null);
this.$store.commit('data/setSampledocsKeywordFilter', null);
this.$store.commit('data/setSampledocsFalsifiedFilter', null);
this.$store.commit('data/setSampledocsIssuedFilter', null);
this.$store.commit('data/setSampledocsCompletedFilter', null);
this.$store.commit('data/setSampledocsSortFilter', null);
this.$store.commit('data/setCurrentPageSampledocs', null);
this.$router.push({ path: '/SampleDocumentsViewAll'});
},
goToSubscribePage(){
this.$router.push({ path: '/Advantage/Subscribe'});
},
paymentFocus(){
this.toggle = !this.toggle;
this.showInfo = !this.showInfo;
},
goToUserProfile(){
this.$router.push({ path: '/UserDashboard'});
},
showLoginModal() {
//
this.$bvModal.show("bv-modal-login");
},
openChartKeys(){
this.$store.commit('data/setResourcesCategoryFilter',{text:"Charts & Keys", value: process.env.NUXT_RESOURCE_CATEGORY_CHARTS});
this.$store.commit('data/setResourcesCountryFilter', null);
this.$store.commit('data/setCurrentPageResources', null);
this.$store.commit('data/setResourcesSortFilter', null);
this.$router.push({ path: '/ResourceBoardViewAll'});
},
openPublications() {
this.$store.commit('data/setResourcesCategoryFilter',{text:"Research & Analysis", value: 18});
this.$store.commit('data/setResourcesCountryFilter', null);
this.$store.commit('data/setCurrentPageResources', null);
this.$store.commit('data/setResourcesSortFilter', null);
this.$router.push({ path: '/ResourceBoardViewAll'});
},
getSubscribeToFormPage() {
return new Promise((resolve, reject) => {
SubscriptionService.subscribeToFormPage()
.then((response) => {
if (response) {
this.subscriptionCost = response.productPrice;
this.institutionName = response.institution;
this.existingSubscriptionId = response.existingSubscriptionId;
this.productId = response.productId;
this.productName = response.productName;
this.userId = response.userId;
this.startDate = response.existingSubscriptionStartDate;
this.endDate = response.existingSubscriptionEndDate;
this.active = response.existingSubscriptionIsActive;
this.canRenew = response.canRenew;
if (response.firstName) this.firstName = response.firstName;
if (response.lastName) this.lastName = response.lastName;
if (this.existingSubscriptionId) this.renewal = true;
this.loading = false;
}
})
.catch((error) => {
let message = '';
try {
if (error.response.data) {
message = error.response.data.status + ' : ' + error.response.data.error;
this.$toast.error(message, {
position: "top-right",
timeout: 5000,
closeOnClick: true,
pauseOnFocusLoss: true,
pauseOnHover: true,
draggable: true,
draggablePercent: 0.6,
showCloseButtonOnHover: false,
hideProgressBar: true,
closeButton: "button",
icon: true,
rtl: false
});
}
else if (error.response && error.response.status === 403) {
message = '403: Insufficient Privileges';
this.$toast.error(message, {
position: "top-right",
timeout: 5000,
closeOnClick: true,
pauseOnFocusLoss: true,
pauseOnHover: true,
draggable: true,
draggablePercent: 0.6,
showCloseButtonOnHover: false,
hideProgressBar: true,
closeButton: "button",
icon: true,
rtl: false
});
}
// else if (error.response.status === 401) {
// this.$nuxt.error({ statusCode: 401, message: 'User is not authenticated' });
// }
this.loading = false;
} catch (e) {
this.loading = false;
this.$nuxt.error(error);
}
});
});
}
}
Nuxt app front end on Azure app service server issue with trailing slash. When refreshing or redirecting, adds slash and routes to old version of page
On Azure App Service, create or modify a web.config
file to normalize URLs and prevent trailing slashes from redirecting to a different cached route:
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="RemoveTrailingSlash" stopProcessing="true">
<match url="(.*)/$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
</conditions>
<action type="Redirect" url="/{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
You can refer to the following Microsoft Q&A documentation for Add RemoveTrailingSlashRule
/SomePage/
redirects to /SomePage
, and the cached version for /SomePage/
is not used.Deploy this file to the root of the Nuxt app’s dist/
or public folder, depending on the deployment type.
Sometimes App Service serves old .nuxt/dist
content from earlier deployments.
Open App Service > Advanced Tools > Kudu > Debug console
Navigate to /home/site/wwwroot/.nuxt
or dist
Manually delete everything and redeploy clean or add a script to the deployment pipeline: rm -rf .nuxt dist