React 应用程序的 API 调用中使用 AWS CloudFront 链接,而不是正确的 API URL

问题描述 投票:0回答:1

要点

由于 AWS CloudFront 发行版的域名被用作 API 的基本 URL,我的 React Web 应用程序的 API 请求失败,状态为 403(禁止)。在浏览器的开发控制台中打开“网络”选项卡,然后尝试登录我的应用程序,我看到请求 URL 如下:

`https://[my_cf_distribution_link]/[my_api_url]/login`

当然应该是:

`https://[my_api_url]/login`

一些额外信息

我的 AWS 管道是使用 CodeBuild、S3 和 CloudFront 设置的。当我在 S3 存储桶上启用静态托管并尝试从存储桶的域登录时,一切都会按预期进行。我尝试过更改 CF 发行版上的各种设置,例如查看器协议行为,但没有任何效果。据我所知,我没有使用 API Gateway 或 Lambda。另外,需要澄清的是,我的 S3 存储桶可以通过适当的存储桶策略公开访问,并且 CF 的原始访问设置也设置为公开。网站内容本身通过 CF 域链接完美地提供服务,实际上只是 API 请求失败了。

我在 React 应用程序中使用 axios 来处理 API 请求。我附上了一些负责发送请求的代码的屏幕截图、URL 和配置的运行时值的浏览器控制台输出以及 API 请求标头。为了保护敏感信息已被删除

code_base

headers

axios amazon-cloudfront
1个回答
0
投票

不确定这是否会对遇到类似问题的人有所帮助,因为我的具体情况的解决方案在于实现 axios 库来请求 API 调用,并且与任何特定的 AWS 配置无关。

罪魁祸首

在我的 React 应用程序中,我有一个类“BaseController”来处理我的所有 API 调用。在类的构造函数中,我从“.env”文件中读取后端的基本 API URL,并将其存储在常量字段中。当发出 API 请求时,我获取 API 的端点(例如“/login”)并将其附加到基本 URL,然后将结果传递给 axios。

import axios from "axios";

const BASE_URL = process.env.REACT_APP_BASE_URL;

export default class BaseController {
    constructor() {
        this.BASE_URL = BASE_URL;
    }

    sendRequest = async (method, url, body) => {

        let config = {
            method: method
        };
        
    url = `${this.BASE_URL}/${url}`;
        
        // Remove any duplicate '/'
        url = url.replace(/\/+/g, "/");

        if (params) {
            config.params = this.addQueryParameters(url, params);
        }

        if (body !== null) {
            config.data = JSON.stringify(body);
        }

        const response = await axios(url, config);

        return response.data;
    };
}

但是,传递给 axios 的 URL 不会被读取为它应该使用的绝对 URL。因此,当从 CloudFront 域发出请求时,axios 使用 CF 域作为其基本 URL。为什么在开发过程中我的本地计算机上甚至在静态托管的 S3 存储桶域中没有发生这种情况,我不知道。

解决方案

正确设置 axios 的默认基本 URL,如下所示:

axios.defaults.baseURL = baseURL;

所以上面的函数看起来像这样:

import axios from "axios";

const BASE_URL = process.env.REACT_APP_BASE_URL;

export default class BaseController {
    constructor() {
        axios.defaults.baseURL = BASE_URL;
    }

    sendRequest = async (method, url, body) => {

        let config = {
            method: method
        };
        
        // Remove any duplicate '/'
        url = url.replace(/\/+/g, "/");

        if (params) {
            config.params = this.addQueryParameters(url, params);
        }

        if (body !== null) {
            config.data = JSON.stringify(body);
        }

        const response = await axios(url, config);

        return response.data;
    };
}

然后就可以像这样使用(非常简化的使用示例):

import BaseController from "./BaseController";

const response = await BaseController.sendRequest("POST", "/login", credentials);

希望这对某人有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.