如何在组件设置脚本之外的 nuxt 3 中使用 env 变量

How to use env variables in nuxt 3 outside of components setup scripts

提问人:wale 提问时间:11/17/2023 最后编辑:Brian Tompsett - 汤莱恩wale 更新时间:11/18/2023 访问量:44

问:

我已经在我的 .env 文件中定义了 API URL,如下所示

const isProdEnv = process.env.NODE_ENV === 'production'
const DEV_API_URL = "https://example-stage.herokuapp.com/v1/"
const PROD_API_URL = "https://example.herokuapp.com/v1/"
const API_URL = isProdEnv ? PROD_API_URL : DEV_API_URL

我的 nuxt 配置文件中有一个运行时配置,如下所示

runtimeConfig: {public: { apiURL: process.env.API_URL || "https://example-stage.herokuapp.com/v1/",     },   },

我想在组件之外使用此 API URL,因为我有集中的 API 调用。我定义了一个像这样调用的可组合项来使用运行时配置:UseApiUrl

export default function useApiUrl() {
  const config = useRuntimeConfig();
  const apiUrl = ref(config.public.apiURL);
  return { apiUrl };
}

我在我的服务/api.js 文件中使用了这个可组合项

import useApiUrl from "~/composables/useApiUrl";
const { apiUrl } = useApiUrl();

export const HTTP = {
  baseURL: apiUrl.value,
  headers: {
    "Content-Type": "application/json",
  },
};

我正在将request.js文件中的HTTP对象用于中心化的HTTP方法,并设置这样的标头

import { HTTP } from "./api";
export default class Req {
  constructor() {
    if (localStorage.getItem("token")) {
      HTTP.headers.Authorization = "JWT " + localStorage.getItem("token");
    } else {
      delete HTTP.headers.Authorization;
    }
  }

  async get(url, queryObject) {
    let runUrl = url;
    if (queryObject) {
      const queryParams = new URLSearchParams();
      for (const key in queryObject) {
        if (Array.isArray(queryObject[key])) {
          queryObject[key].forEach((value) => queryParams.append(key, value));
        } else {
          queryParams.append(key, queryObject[key]);
        }
      }
      runUrl = url + "?" + queryParams.toString();
    }

    try {
      const response = await fetch(HTTP.baseURL + runUrl, {
        method: "GET",
        headers: HTTP.headers,
      });

      if (!response.ok) {
        throw new Error("Network response was not ok");
      }

      return await response.json();
    } catch (error) {
      throw error;
    }
  }
  async post(url, payload) {
    try {
      const headers = { ...this.headers };

      if (payload instanceof FormData) {
        delete headers["Content-Type"];
      } else {
        headers["Content-Type"] = "application/json";
      }

      const token = localStorage.getItem("token");
      if (token) {
        headers["Authorization"] = "JWT " + token;
      }

      const response = await fetch(HTTP.baseURL + url, {
        method: "POST",
        headers: headers,
        body:
          (payload instanceof FormData && payload) || JSON.stringify(payload),
      });
      if (!response.ok) {
        throw response;
      }

      return await response.json();
    } catch (error) {
      console.log(error);
      throw error;
    }
  }
  async put(url, payload) {
    try {
      const response = await fetch(HTTP.baseURL + url, {
        method: "PUT",
        headers: HTTP.headers,
        body: JSON.stringify(payload),
      });

      if (!response.ok) {
        throw new Error("Network response was not ok");
      }

      return await response.json();
    } catch (error) {
      throw error;
    }
  }

  async patch(url, payload) {
    // Implement similarly to post
    try {
      const response = await fetch(HTTP.baseURL + url, {
        method: "PATCH",
        headers: HTTP.headers,
        body: JSON.stringify(payload),
      });

      if (!response.ok) {
        throw new Error("Network response was not ok");
      }

      return await response.json();
    } catch (error) {
      throw error;
    }
  }

  async delete(url) {
    // Implement similarly to post
    try {
      const response = await fetch(HTTP.baseURL + url, {
        method: "DELETE",
        headers: HTTP.headers,
      });

      if (!response.ok) {
        throw new Error("Network response was not ok");
      }

      return await response;
    } catch (error) {
      throw error;
    }
  }
}

我收到这个错误

[努克斯特]需要访问 Nuxt 实例的可组合项是在插件、Nuxt 钩子、Nuxt 中间件或 Vue 设置函数之外调用的。

谁能帮我了解如何在组件文件外部公开API_URL?

我需要使用 api.js 文件中的API_URL。

javascript vue.js nuxt.js fetch nuxtjs3

评论

0赞 Boussadjra Brahim 11/17/2023
如何使用 HTTP 对象?
1赞 Estus Flask 11/17/2023
它可能不应该。使用可组合项的位置应该是另一个可组合项,例如 useHttpOptions。可能你需要一个用于获取的包装器来添加选项
0赞 wale 11/17/2023
@BoussadjraBrahim我在请求中使用 HTTP 对象.js 文件具有集中的 HTTP 方法并设置如下所示的标头import { HTTP } from "./api"; export default class Req { constructor() { if (localStorage.getItem("token")) { HTTP.headers.Authorization = "JWT " + localStorage.getItem("token"); } else { delete HTTP.headers.Authorization; } }
0赞 Denis Sinyukov 11/17/2023
你试过RunWithContext了吗?

答:

2赞 Ellrohir 11/18/2023 #1

我无法从片段中真正重现您的整个代码,但我相信有问题的调用在内部。因为像这样写成独立的常量,所以它是在加载文件时执行的,而不是在任何代码内部调用时执行的。const { apiUrl } = useApiUrl();services/api.js<script setup>

您应该将其包装在函数调用中,以避免在上下文之外调用。

我有一个想法,但不确定它是否会像这样工作。如果有问题,请告诉我,并希望我们能设法弄清楚。

我会试着变成:services/api.jscomposables/useHTTP.js

export useHttp = () => {
  const HTTP = {
    baseURL: useApiUrl().value,
    headers: {
      "Content-Type": "application/json",
    },
  };
  return { HTTP };
};

然后在:request.js

export default class Req {
  constructor() { 
    this.HTTP = useHttp().HTTP
    if (localStorage.getItem("token")) {
      this.HTTP.headers.Authorization = "JWT " + localStorage.getItem("token");
    } else {
      delete this.HTTP.headers.Authorization;
    }
  }

  ...

}

像这样,需要可组合项的代码不应早于第一次需要类实例时调用。这应该已经在里面了。Req<script setup>

评论

1赞 wale 11/18/2023
这使用 useHTTP 可组合项 谢谢:)