如何在 Nuxt 中使用私钥 API(在客户端)?
How to use a private API key with Nuxt (on the client)?
问题已解决
如果您遇到同样的问题,请查看已接受的答案,这是使用 serverMiddleware
实现该问题的一种方法
我正在使用需要私钥的 API。我已将密钥存储在 .env 文件中,并在 nuxt 配置文件中调用它,如下所示:
privateRuntimeConfig: {
secretKey: process.env.MY_SECRET_KEY
},
我的 API 调用是在我的索引页上的 asyncData() 挂钩内完成的。当我加载或重新加载此页面时它工作正常,但每次我使用导航返回此页面时,我都会遇到错误(我使用缓冲区将我的 API 密钥转换为 base64)
First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.
经过一些研究和调试,我发现当时我的私钥不可用,我的 api 调用中使用的“秘密”值是“未定义”。
我不明白的是为什么这在初始加载/重新加载时有效,但在页面导航时无效?有没有办法在不使用后端的情况下修复它? (用于 SEO 的 SSR 和使用私钥而不暴露私钥的能力是我在我的项目中使用 Nuxt 的主要原因)
这是我的代码:
async asyncData({ $content, store, $config }) {
const secret = Buffer.from($config.secretKey).toString('base64')
const request = await fetch('https://app.snipcart.com/api/products', {
headers: {
'Authorization': `Basic ${secret}`,
'Accept': 'application/json'
}
})
const result = await request.json()
store.commit('products/addProducts', result)
const stocks = store.getters['products/getProducts']
return { stocks }
},
更新:
当从 API 调用所在的页面以外的任何其他页面访问网站时,它不起作用,因为商店不会有来自 API 调用的任何数据)
好吧,现在我觉得自己很笨。我找到了让它工作的方法。我想花时间解释我的问题有助于我理解如何解决它。
对于那些遇到类似问题的人,我通过用 If 语句包装 API 调用来修复它。
if ($config.secretKey) {
const secret = Buffer.from($config.secretKey).toString('base64')
const request = await fetch('https://app.snipcart.com/api/products', {
headers: {
'Authorization': `Basic ${secret}`,
'Accept': 'application/json'
}
})
const result = await request.json()
store.commit('products/addProducts', result)
}
const stocks = store.getters['products/getProducts']
这样,我可以跳过 API 调用并从我的 vuex 存储中访问值。
更新
查看 @nuxtjs/snipcart
module's key 键,因为它是 buildModules
,你完全可以把它放在那里,因为它只在构建期间可用(在 Node.js 仅)!
有关更多信息,Snipcart 确实有很多博客文章,这篇基于 Nuxt 的文章可能有助于清理问题:https://www.storyblok.com/tp/how-to-build-a-shop-with-nuxt-storyblok-and-snipcart
你最初确实有你的密钥,因为当你进入页面或硬刷新它时你正在访问服务器。
如果您在 hydration 之后导航,它将是客户端导航,因此您将无法访问私钥。最后,如果您的密钥 确实 私有(现在,一些 API 提供可以公开的密钥),您需要以某些方式解决它。
查看 Snipcart:https://docs.snipcart.com/v3/api-reference/authentication,它明确指出密钥应该在
中可用
Appear in your compiled front-end assets (HTML, JavaScript)
与此同时,如果您需要再次调用后端(尝试访问 products
以外的内容),则需要进行第二次调用。
使用 Nuxt2,您现在无法每次都访问后端,因为您将停留在 SPA 上下文中(Nuxt 是 server
then client
Vue 应用程序基本上)。但是您可以将令牌写到 cookie 中,甚至更好,使用后端作为代理来隐藏此特定密钥(甚至是无服务器功能)。
可以在我的其他答案中找到更多信息:
感谢@kissu 的(非常)快速回答:)
所以,根据你所说的和你对这个问题的其他回答,我在我的服务器文件夹中用 Nuxt 创建了一个服务器中间件。
server/snipcart.js
const bodyParser = require('body-parser')
const axios = require('axios')
const app = require('express')()
app.use(bodyParser.json())
app.all('/getProducts', (request, response) => {
const url = 'https://app.snipcart.com/api/products'
const secret = Buffer.from(process.env.SNIPCART_SECRET).toString('base64')
const config = {
headers: {
'Authorization': `Basic ${secret}`,
'Accept': 'application/json'
}
}
axios
.get(url, config)
.then(res => {
const products = {}
res.data.items.forEach(
item => {
const productId = item.userDefinedId.replace(/-/g, '')
const stocks = {}
item.variants.forEach(
variant => {
const size = variant.variation[0].option
const stock = variant.stock
stocks[size] = stock
}
)
products[productId] = stocks
}
)
response.json(products)
})
.catch( err => response.json(err) )
})
module.exports = app
如果我错了请纠正我,但我认为这与使用服务器作为代理基本相同,对吗?基于 Nuxt 生命周期挂钩,serverMiddleware 一个在服务器上只有 运行,所以我的 API 密钥不应该暴露给客户端? (我仍然需要做一些重构来清理代码,但至少它在工作)(https://nuxtjs.org/docs/concepts/nuxt-lifecycle/#server & https://nuxtjs.org/docs/configuration-glossary/configuration-servermiddleware/)
nuxt.config.js
serverMiddleware: [
{ path: "/server", handler: "~/server/snipcart.js" }
]
index.vue(我的 snipcart API 调用是以前进行的,我想现在我应该直接从需要数据的产品卡组件中移动这个调用):
async asyncData({ $content, store, $axios }) {
await $axios
.get('/server/getProducts')
.then(res => store.commit('products/addProducts', res.data))
.catch(err => console.log(err))
const stocks = store.getters['products/getProducts']
return {stocks, masterplanProducts }
},
PS : Snipcart 确实提供了 public API 键,但是使用非常有限。为了访问每个产品的剩余库存,我必须使用私钥(它允许一些其他操作,比如删除产品/访问订单等)
问题已解决
如果您遇到同样的问题,请查看已接受的答案,这是使用 serverMiddleware
实现该问题的一种方法我正在使用需要私钥的 API。我已将密钥存储在 .env 文件中,并在 nuxt 配置文件中调用它,如下所示:
privateRuntimeConfig: {
secretKey: process.env.MY_SECRET_KEY
},
我的 API 调用是在我的索引页上的 asyncData() 挂钩内完成的。当我加载或重新加载此页面时它工作正常,但每次我使用导航返回此页面时,我都会遇到错误(我使用缓冲区将我的 API 密钥转换为 base64)
First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.
经过一些研究和调试,我发现当时我的私钥不可用,我的 api 调用中使用的“秘密”值是“未定义”。
我不明白的是为什么这在初始加载/重新加载时有效,但在页面导航时无效?有没有办法在不使用后端的情况下修复它? (用于 SEO 的 SSR 和使用私钥而不暴露私钥的能力是我在我的项目中使用 Nuxt 的主要原因)
这是我的代码:
async asyncData({ $content, store, $config }) {
const secret = Buffer.from($config.secretKey).toString('base64')
const request = await fetch('https://app.snipcart.com/api/products', {
headers: {
'Authorization': `Basic ${secret}`,
'Accept': 'application/json'
}
})
const result = await request.json()
store.commit('products/addProducts', result)
const stocks = store.getters['products/getProducts']
return { stocks }
},
更新:
当从 API 调用所在的页面以外的任何其他页面访问网站时,它不起作用,因为商店不会有来自 API 调用的任何数据)
好吧,现在我觉得自己很笨。我找到了让它工作的方法。我想花时间解释我的问题有助于我理解如何解决它。
对于那些遇到类似问题的人,我通过用 If 语句包装 API 调用来修复它。
if ($config.secretKey) {
const secret = Buffer.from($config.secretKey).toString('base64')
const request = await fetch('https://app.snipcart.com/api/products', {
headers: {
'Authorization': `Basic ${secret}`,
'Accept': 'application/json'
}
})
const result = await request.json()
store.commit('products/addProducts', result)
}
const stocks = store.getters['products/getProducts']
这样,我可以跳过 API 调用并从我的 vuex 存储中访问值。
更新
查看 @nuxtjs/snipcart
module's key 键,因为它是 buildModules
,你完全可以把它放在那里,因为它只在构建期间可用(在 Node.js 仅)!
有关更多信息,Snipcart 确实有很多博客文章,这篇基于 Nuxt 的文章可能有助于清理问题:https://www.storyblok.com/tp/how-to-build-a-shop-with-nuxt-storyblok-and-snipcart
你最初确实有你的密钥,因为当你进入页面或硬刷新它时你正在访问服务器。
如果您在 hydration 之后导航,它将是客户端导航,因此您将无法访问私钥。最后,如果您的密钥 确实 私有(现在,一些 API 提供可以公开的密钥),您需要以某些方式解决它。
查看 Snipcart:https://docs.snipcart.com/v3/api-reference/authentication,它明确指出密钥应该在
中可用Appear in your compiled front-end assets (HTML, JavaScript)
与此同时,如果您需要再次调用后端(尝试访问 products
以外的内容),则需要进行第二次调用。
使用 Nuxt2,您现在无法每次都访问后端,因为您将停留在 SPA 上下文中(Nuxt 是 server
then client
Vue 应用程序基本上)。但是您可以将令牌写到 cookie 中,甚至更好,使用后端作为代理来隐藏此特定密钥(甚至是无服务器功能)。
可以在我的其他答案中找到更多信息:
感谢@kissu 的(非常)快速回答:)
所以,根据你所说的和你对这个问题的其他回答,我在我的服务器文件夹中用 Nuxt 创建了一个服务器中间件。
server/snipcart.js
const bodyParser = require('body-parser')
const axios = require('axios')
const app = require('express')()
app.use(bodyParser.json())
app.all('/getProducts', (request, response) => {
const url = 'https://app.snipcart.com/api/products'
const secret = Buffer.from(process.env.SNIPCART_SECRET).toString('base64')
const config = {
headers: {
'Authorization': `Basic ${secret}`,
'Accept': 'application/json'
}
}
axios
.get(url, config)
.then(res => {
const products = {}
res.data.items.forEach(
item => {
const productId = item.userDefinedId.replace(/-/g, '')
const stocks = {}
item.variants.forEach(
variant => {
const size = variant.variation[0].option
const stock = variant.stock
stocks[size] = stock
}
)
products[productId] = stocks
}
)
response.json(products)
})
.catch( err => response.json(err) )
})
module.exports = app
如果我错了请纠正我,但我认为这与使用服务器作为代理基本相同,对吗?基于 Nuxt 生命周期挂钩,serverMiddleware 一个在服务器上只有 运行,所以我的 API 密钥不应该暴露给客户端? (我仍然需要做一些重构来清理代码,但至少它在工作)(https://nuxtjs.org/docs/concepts/nuxt-lifecycle/#server & https://nuxtjs.org/docs/configuration-glossary/configuration-servermiddleware/)
nuxt.config.js
serverMiddleware: [
{ path: "/server", handler: "~/server/snipcart.js" }
]
index.vue(我的 snipcart API 调用是以前进行的,我想现在我应该直接从需要数据的产品卡组件中移动这个调用):
async asyncData({ $content, store, $axios }) {
await $axios
.get('/server/getProducts')
.then(res => store.commit('products/addProducts', res.data))
.catch(err => console.log(err))
const stocks = store.getters['products/getProducts']
return {stocks, masterplanProducts }
},
PS : Snipcart 确实提供了 public API 键,但是使用非常有限。为了访问每个产品的剩余库存,我必须使用私钥(它允许一些其他操作,比如删除产品/访问订单等)