如何使用私有API密钥与next(在客户端)?



问题解决

如果你正在为同样的问题而挣扎,看看公认的答案,这是通过使用serverMiddleware来实现它的一种方法


我正在使用一个需要私钥的API。我将密钥存储在.env文件中,并在下一个配置文件中调用它,如下所示:

privateRuntimeConfig: {
secretKey: process.env.MY_SECRET_KEY
},

我的API调用是在我的索引页的asyncData()钩子内完成的。它的工作很好,当我加载这个页面,或重新加载它,但每次我使用导航回到这个页面,我结束了一个错误(我使用缓冲区转换我的API密钥为base64)

第一个参数必须是字符串、Buffer、ArrayBuffer、Array或类数组对象。

经过一番研究和调试,我发现我的私钥当时不可用,并且"秘密"在我的API调用中使用的值是"未定义"。

我不明白的是为什么这是在初始加载/重新加载工作,而不是在页面导航?有没有一种方法来修复它,而不使用后端?(SEO的SSR和使用私钥而不暴露它们的能力是我在我的项目中使用next的主要原因)

下面是我的代码:
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 }
},

更新

查看@nuxtjs/snipcart模块的key key,因为它是buildModules,你可以完全把它放在那里,因为它只在构建期间可用(仅在Node.js上)!

要了解更多信息,Snipcart确实有很多博客文章,这篇基于next的文章可能有助于澄清问题:https://www.storyblok.com/tp/how-to-build-a-shop-with-nuxt-storyblok-and-snipcart


当您进入页面或硬刷新它时,您最初确实有您的密钥,因为您正在到达服务器。

如果您在水合化之后导航,它将是客户端导航,因此您将无法访问私钥。最后,如果你的键是,真的是private(现在,一些API提供了可以公开的密钥),您需要以某种方式解决它。

查看Snipcart: https://docs.snipcart.com/v3/api-reference/authentication,它清楚地说明了键应该在

中可用。

出现在编译后的前端资产(HTML, JavaScript)

同时,如果你需要给你的后端打另一个电话(试图访问products以外的东西),你需要打第二个电话。

使用Nuxt2,由于您将停留在SPA上下文中(Nuxt2是server然后),因此您不能每次都访问后端。clientVue应用程序基本上)。但是您可以将令牌写入cookie,或者更好的是,使用后端作为代理来隐藏此特定密钥(甚至是无服务器功能)。

更多信息可以在我的其他回答中找到:https://stackoverflow.com/a/69575243/8816585

感谢@kissu的快速回答:)

所以,根据你所说的和你对这个主题的其他回答,我在我的服务器文件夹中做了一个服务器中间件。

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  

纠正我,如果我错了,但我认为这基本上是相同的使用服务器作为代理对吗?基于next生命周期钩子,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" }
]

索引。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确实提供了一个公共API密钥,但使用非常有限。为了访问每个产品的剩余库存,我必须使用私钥(它允许一些其他操作,如删除产品/访问订单等)

UPDATE:

当网站从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存储访问值。