使用服务器端而不是客户端来查询API?

时间:2020-08-28 17:57:40

标签: node.js reactjs express axios

目前,我正在像这样的React组件中使用不希望公开的API密钥调用API:

useEffect(() => {
  const fetchData = () => {
    const url = `API_URL+${searchedValue}+process.env.API_KEY`;
    fetch(url, { headers: { Accept: 'application/json' } })
      .then(res => res.json()
      .then((json) => {
        setData(json.data || []);
       }))
    .catch(err => console.error(err)); // eslint-disable-line
  };
  debounce(fetchData());
}, [searchedValue]);

它可以完美工作,但是我知道这是错误的,因为它发生在反应端,很容易有人发现我的API密钥。我检查了网络日志,可以看到我的查询已发送到API,API密钥等。在阅读了有关如何解决此问题的内容后,我开始实现基本服务器:

const express = require("express")
  app = express(),
  cors = require("cors");

app.use(cors());
app.listen(process.env.PORT || 3000);

app.get("/", (req, res) => {
  res.send({ message: "Server Connected" });
});

现在,我想我知道需要做些什么。而不是直接在react端调用API,而是使用诸如/ api-$(searchedValue)之类的请求来查询服务器(searchedValue,因为我的查询取决于用户搜索的值)。此后,我的服务器查询实际的API,并返回从API获得的响应。

如果我对此流程的理解不正确,请纠正我^

但是,我完全不知道如何更改这两个文件来实现。我还没有在线找到任何教程。也许,有人可以告诉我如何实现预定目标?我正在使用ReactJS,Redux,Axios,Express和Node.JS-预先感谢。

2 个答案:

答案 0 :(得分:0)

我认为您正在寻找的概念是 BFF (前端后端),您可以使用它来隐藏API密钥。 使用这种方法,您必须在Express服务器中创建另一个端点来使用API​​密钥进行请求,并继续在前端进行请求,但是对于Express Server上的新端点来说,这是一个简单的请求,因此密钥只能位于您的BFF中(表示)。

另一种方法是服务器端渲染,您可以在服务器上执行并生成包含所需数据的HTML,然后将整个页面发送到前端。您可以使用Next.js轻松实现这一目标。

答案 1 :(得分:0)

那么,在客户端使用API​​密钥是有风险且不安全的。在Webapp的生命周期中,您将需要某种服务器。您只能使用express / hapi / Koa或其他服务器端框架将API密钥发送到前端。只需调用为您提供API密钥的终结点并初始化客户端存储的(Redux / Recoil / Context)API凭据即可。

客户

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: io.github.andre00nogueira.myapplication, PID: 10135
    java.lang.RuntimeException: Unable to start activity ComponentInfo{io.github.andre00nogueira.myapplication/io.github.andre00nogueira.myapplication.MainActivity}: javax.crypto.AEADBadTagException
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: javax.crypto.AEADBadTagException
        at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:517)
        at javax.crypto.Cipher.doFinal(Cipher.java:2055)
        at io.github.andre00nogueira.myapplication.WRAPPER.decrypt(WRAPPER.kt:73)
        at io.github.andre00nogueira.myapplication.MainActivity.onCreate(MainActivity.kt:29)
        at android.app.Activity.performCreate(Activity.java:7802)
        at android.app.Activity.performCreate(Activity.java:7791)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
     Caused by: android.security.KeyStoreException: Signature/MAC verification failed
        at android.security.KeyStore.getKeyStoreException(KeyStore.java:1292)
        at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:224)
        at android.security.keystore.AndroidKeyStoreAuthenticatedAESCipherSpi$BufferAllOutputUntilDoFinalStreamer.doFinal(AndroidKeyStoreAuthenticatedAESCipherSpi.java:373)
        at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)

但是请在应用程序的顶层调用 API密钥提供端点,以便您可以从任何其他组件轻松访问它...

//App.js
useEffect(() => {
  const fetchData = () => {
    fetch("/some-secure-endpoint", { headers: { Accept: 'application/json' } })
      .then(res => res.json()
      .then((json) => {
        setData(json.data || []);
        //redux approach
        dispatch(setCredentials(json));
       }))
    .catch(err => console.error(err)); // eslint-disable-line
  };
}, [searchedValue]);

这是一种经典方法,适用于中小型项目。通过研究一段时间,尝试更安全的方法。