Nuxt.js: Nuxt server $nuxt.context changed by latter request

Created on 10 Jul 2020  Â·  5Comments  Â·  Source: nuxt/nuxt.js

How do I discover this problem?

In production env, I use $nuxt.context.route info to determine which header to show ( use v-if ) in defaultLayout(which is shared between all routes), because we believe $nuxt.context should be the same in one request, but turn out not the same.
In large concurrent request , Accidentally A page will display B page header, which should only be displayed in B page, so I print out the $nuxt.context.route.name , but unfortunately printed B when refresh A page, then we printed out some $nuxt.context info which is also related to B page when refresh A page

So I did a simple demo below to reproduce the problem, hope this unknown but important issue be addressed quickly

Versions

  • nuxt: 2.10.2
  • node: v8.11.2

Steps to reproduce

  1. create a nuxt project
  2. add 2 simple vue files to mimic 2 routes:

./pages/index.vue
./pages/B.vue

  1. change ./layouts/default.vue to below content
<template>
  <div>
    <p>{{ $route.name }}</p>

    <p>{{ $nuxt.context.route.name }}</p>

    <Nuxt />
  </div>
</template>
<script>
export default {
  created() {
    setTimeout(() => {
      console.log('--------', this.$route.name, this.$nuxt.context.route.name)
    }, 1000)
  },
}
</script>
  1. visit http://localhost:3000/ then quickly visit http://localhost:3000/b

What is Expected?

on both client and server side
1 second later, print out

-------- index index
-------- B B

What is actually happening?

1 second later
client side print out the same as expected

-------- index index
-------- B B

But server side terminal print out

-------- index B
-------- B B

Conclusion

It's obvious that first visited page index this.$nuxt.context is alter by second request (which visited page B)

Anybody know why? Is it a bug or a usage problem?

bug-report

Most helpful comment

I can replicate this bug. The issue is not that $nuxt.context is shared, but rather that a different $nuxt (with a different context) is being assigned to the global Vue on each instantiation.

https://github.com/nuxt/nuxt.js/blob/757d5d46dad6a8b0698a944602f45b8bc59dde7b/packages/vue-app/template/App.js#L101

Repro
https://github.com/danielroe/nuxt-shared-state

yarn
yarn dev
curl http://localhost:3000/about/bob ; curl http://localhost:3000/about

All 5 comments

I also encountered a very strange phenomenon and same like @wizardpisces

I have a shared common component, named common.vue for example. And two page componentsPageA.vue ,PageB.vue

I generate a requestId and set it to node.js req, and set response header to the page response x-request-id

// common.vue
<template>
  <div>
    <p>{{ $nuxt.context.req.requestId }} {{ $nuxt.context.route.name }} {{ $route.name }}</p>
  </div>
</template>
<script lang="ts">
import { Component } from 'nuxt-property-decorator'

@Component({
  components: {

  }
})
export default class LayoutDefault extends Vue {
  created() {
    const { route, req } = this.$nuxt.context
    if (process.server) {
      console.log('---------------------main.vue----start------------------')
      console.log('+++++main.vue++++++$nuxt.context.req', req.requestId)
      console.log('+++++main.vue++++++$nuxt.context.route', route.name)
      console.log('++++++main.vue++++++this.$route', this.$route.name)
      console.log('---------------------main.vue----end------------------')
    }
  }
}
</script>

When I visit page B, at the same time,I visit page A, the response HTML does not meet expectations。

image

The page requestId is e6843d37 , when create common.vue, the terminal console 5ef26a44, the previous requestId, and the $route.name $nuxt.route.name Is unexpected.

Am I use the wrong way?

Thanks for your contribution to Nuxt.js!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you would like this issue to remain open:

  1. Verify that you can still reproduce the issue in the latest version of nuxt-edge
  2. Comment the steps to reproduce it

Issues that are labeled as pending will not be automatically marked as stale.

So much time passed, is there anyone in the nuxt committee care to spend some time on this issue?

I can replicate this bug. The issue is not that $nuxt.context is shared, but rather that a different $nuxt (with a different context) is being assigned to the global Vue on each instantiation.

https://github.com/nuxt/nuxt.js/blob/757d5d46dad6a8b0698a944602f45b8bc59dde7b/packages/vue-app/template/App.js#L101

Repro
https://github.com/danielroe/nuxt-shared-state

yarn
yarn dev
curl http://localhost:3000/about/bob ; curl http://localhost:3000/about

Package versions:

"@nuxtjs/composition-api": "^0.12.5",
"nuxt": "^2.14.6",
"nuxt-i18n": "^6.15.1",

Guys, I am facing this exactly same issue and in my case it's very very bad since the first segment of the URL define a customer of my platform which will be used to build up the metatags.
Basically if you share a link of the business A on Facebook, WhatsApp or any platform that creates the link preview you might see the details of the business B - and there is a big chance of they be competitors.

I've tried the solution proposed on #8068 #8132 using npm link, but no success... looks like that is not going to solve the issue.

To give you guys a bit of context, before I refactor some components in my app (up to this point it was working fine), this was my implementation:

I use the nuxtServerInit to fetch the business information based in a router param.
/store/index.js

export const actions = {
  async nuxtServerInit({ dispatch }, { params, $sentry }) {
    const businessSlug = params.businessSlug

    try {
      // this dispatch calls a vuex action that will fetch the business details - that later will be used to feed the metatags
      // and save the business in the vuex state
      const business = await dispatch('business/fetchBusiness', businessSlug)
    } catch (e) {
      $sentry.captureException(e)
    }

    // do some more stuff
  },
}

Then I update the metatags based on the vuex state fetch on the nuxtServerInit through the default layout.
* layouts/default.vue*

<script>
import { mapGetters, } from 'vuex'

export default {
  name: 'LayoutDefault',
  computed: {
    ...mapGetters({
      // this was fetch during the nuxtServerInit
      business: 'business/getData',
    }),
  },
  head() {
    const i18nSeo = this.$nuxtI18nSeo()
    const favicon = this.business.logo ?? '/favicon/favicon.png'
    const title = `Order from ${this.business.name}`
    const description = `Order from ${this.business.name} description`

    return {
      title,
      htmlAttrs: {
        ...i18nSeo.htmlAttrs,
      },
      meta: [
        {
          hid: 'description',
          name: 'description',
          content: description,
        },
        // plus other metatags
        ...i18nSeo.meta,
      ],
      link: [
        {
          hid: 'favicon',
          rel: 'image/png',
          href: `${favicon}?w=250&h=250`,
        },
        // plus other links
        ...i18nSeo.link,
      ],
    }
  },
}
</script>

After a refactoring to move the default layout to a composition api structure, the issue started happening!
So my nuxtServerInit hasn't changed, what I did is below:

/layouts/default.vue

<template>
  <div>
    <nuxt />
  </div>
</template>

<script lang="ts">
import { defineComponent, useContext, useMeta } from '@nuxtjs/composition-api'
import type { SetupContext } from '@nuxtjs/composition-api'
import { useSystemBootstrap } from '~/composable/system-bootstrap'

export default defineComponent({
  name: 'LayoutsBusiness',
  head: {},
  setup(_, { root }: SetupContext) {
    const { store } = useContext()

    const nuxtI18nSeo = root.$nuxtI18nSeo()
    const favicon = business.logo || '/favicon/favicon.png'
    const title = `Order from ${business.name}`
    const description = `Order from ${business.name} description.`

    useMeta({
      title,
      htmlAttrs: {
        ...nuxtI18nSeo.htmlAttrs,
      },
      meta: [
        {
          hid: 'description',
          name: 'description',
          content: description,
        },
        // plus other metatags
        ...(nuxtI18nSeo.meta ?? []),
      ],
      link: [
        {
          hid: 'favicon',
          rel: 'image/png',
          href: `${favicon}?w=250&h=250`,
        },
        // plus other links
        ...(nuxtI18nSeo.link ?? []),
      ],
    })

    return {}
  },
})
</script>

Do you guys have any clue on what it could be?

@pi0 @clarkdo @danielroe also, we should considering reopening this issue since it's still happening!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

msudgh picture msudgh  Â·  3Comments

shyamchandranmec picture shyamchandranmec  Â·  3Comments

lazycrazy picture lazycrazy  Â·  3Comments

uptownhr picture uptownhr  Â·  3Comments

mattdharmon picture mattdharmon  Â·  3Comments