使用 POST API 时出现多个 CORS 错误

Posted

技术标签:

【中文标题】使用 POST API 时出现多个 CORS 错误【英文标题】:Getting multiple CORS errors while using POST API 【发布时间】:2019-12-28 20:05:26 【问题描述】:

我在尝试通过 POST 请求上传图像时遇到多个 CORS 错误。我在 AWS API Gateway 上创建了一个 POST API,它触发了一个用 Node js 编写的 lambda 函数。该 API 可以与 Postman 一起正常工作,因为它允许 CORS,但在不同的浏览器上会出现多个错误。

错误如下:-

在 Firefox 上

在 Chrome 上

以下是请求标头:-

Method request headers: 
        sec - fetch - mode = cors,
        sec - fetch - site = cross - site,
        accept - language = en - US,
        en;q = 0.9,
        hi;q = 0.8,
        access - control - allow - headers = Origin,
        X - Requested - With,
        Content - Type,
        Accept,
        Authorization,
        origin = null,
        User - Agent = Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(Khtml, like Gecko) Chrome / 76.0 .3809 .100 Safari / 537.36,
        X - Forwarded - Proto = https,
        Host = xxxxxxx.execute - api.us - east - 2. amazonaws.com,
        X - Forwarded - Port = 443,
        X - Amzn - Trace - Id = Root = 1 - 5 d5fd816 - 4 c1ac880ed09a50047ecda00,
        accept = * /*, access-control-allow-origin=*, X-Forwarded-For=103.97.240.210, content-type=application/json, accept-encoding=gzip, deflate, br

Chrome 上的请求标头

以下是**响应标头:-**

Endpoint response headers: 
    Date = Fri,
    23 Aug 2019 12: 12: 07 GMT,
    Content - Type = application / json,
    Content - Length = 1077,
    Connection = keep - alive,
    x - amzn - RequestId = 46 a264c2 - 44 d7 - 4026 - 9168 - f227e758f078,
    X - Amz - Function - Error = Unhandled,
    x - amzn - Remapped - Content - Length = 0,
    X - Amz - Executed - Version = $LATEST,
    X - Amzn - Trace - Id = root = 1 - 5 d5fd816 - 4 c1ac880ed09a50047ecda00;sampled = 0

邮递员的响应标头

下面是我的代码 客户端:index.html

<body>

<form method="post" enctype="application/json">

    Enter the Employee Id: <input type="text" name="empId"><br>
    Upload the Employee Photo: </h2><input type="file" name="PhotoName"> <br>
    <input type="submit" name="PhotoContent" value="Upload Photo"><br><br>
</form>
</div>

 <script src="upload.js"></script>

</body>

客户端:upload.js

const url = 'https://xxxxxxx.execute-api.us-east-2.amazonaws.com/test/upload';
const form = document.querySelector('form');

form.addEventListener('submit', e => 
    e.preventDefault();

    const files = document.querySelector('[type=file]').files;


    const reader = new FileReader() 
    reader.onload = handleFileLoad;
    reader.readAsBinaryString(files[0]);
    for (let i = 0; i < files.length; i++) 
        let file = files[i];
        console.log(file);

    

);

function handleFileLoad(event) 
    console.log(event);
    let formData = new FormData();
    formData.append('data', event.target.result);
    console.log('final file ', formData.get('data'));

    let data = 
        "fileName" : 'tmp123',
        "user_avatar" : event.target.result
    ;

    fetch(url, 
        method: 'POST',
        body: JSON.stringify(data),
        headers : 
            'Origin' : 'https://xxxxxxx.execute-api.us-east-2.amazonaws.com/test/upload',
            'content-type' : 'application/json',
            'Access-Control-Allow-Origin' : '*',
            'Access-Control-Allow-Headers' : 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
        ,
    ).then(response => 
        console.log(response);
    );

服务器端(lambda):index.js

const AWS = require('aws-sdk');
const  parse  = require('querystring');
var s3 = new AWS.S3();
exports.handler = (event, context, callback) =>    
    if (event.method === 'POST') 
    let body = '';
    event.on('data', chunk => 
        body += chunk.toString();
    );
    req.on('end', () => 
        console.log(
            parse(body)
        );
        res.end('ok');
    );

    //  var event = ' "user_avatar": "asas" ' ;

    let encodedImage = JSON.parse(event.body).user_avatar;
    let decodedImage = Buffer.from(encodedImage, 'base64');
    //  var filePath = "avatars/" + event.queryStringParameters.username + ".jpg"
     var filePath = JSON.parse(event.body).file_name

     var params = 
       "Body": decodedImage,
       "Bucket": "test-bkt-rahul",
       "Key": filePath  
    ;
    s3.upload(params, function(err, data)
       if(err) 
           callback(err, null);
        else 
           let response = 
        "statusCode": 200,
        "headers": 
            "Access-Control-Allow-Origin": ""
        ,
        "body": JSON.stringify(data),
        "isBase64Encoded": false
    ;
           callback(null, response);
    
    );

;

任何建议将不胜感激。提前致谢。

【问题讨论】:

CORS 标头应该在服务器端设置。尝试将 'Access-Control-Allow-Origin' : '*''Access-Control-Allow-Headers' : 'Origin, X-Requested-With, Content-Type, Accept, Authorization' 添加到服务器的响应中。 嗨@Teh,即使在将上述标头添加到服务器端Node js代码之后,我仍然遇到同样的错误。 @Teh 我还有一个疑问是,如果我已经在 OPTIONS 方法上启用了 CORS 标头,我是否还必须为同一资源下的 POST 方法添加相同的标头?因为目前,我已经在 OPTIONS 方法上启用了 CORS,并且还从 POST 方法的 Node Js 代码发送了相同的标头。它会在标题中产生冲突吗? 【参考方案1】:

将 Access-Control-Allow-Oriigin 设置为 null 将禁止所有来源。改为将其设置为 *

"headers": 
            "Access-Control-Allow-Origin": "*"
        ,

【讨论】:

我已经在服务器端和客户端代码中添加了 "Access-Control-Allow-Origin": "*" 标头。我仍然收到相同的 CORS 错误。 您发布的代码另有说明,但没关系。客户端不需要它,它是一个响应头。【参考方案2】:

终于,问题解决了。

我收到了 403 响应代码,因为我使用了不正确的端点。 我收到 CORS 错误,因为我的服务器端代码没有进行异常处理。异常情况下,代码未在响应中发送 CORS 标头。

【讨论】:

【参考方案3】:

您需要为您的资源创建一个 OPTIONS 方法,并使用一个 MOCK 响应将这些标头发回,并在 API 网关上允许这些标头。如果您在 api gateway 上选择您的资源并单击顶部下拉菜单,单击启用 cors,它将为您设置该资源/方法,并带您完成一个直观的工作流程,以允许这些并在它们之间来回传递它们的值客户端和您的后端(在本例中为 lambda)。

您还可以指定允许的方法,'*' 或子集('GET,POST')

试试这些:

"Access-Control-Allow-Methods": "'*'",
"Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'",
"Access-Control-Allow-Origin": "'*'"

AWS API Gateway CORS 文档:https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html

【讨论】:

感谢您的回复。我在创建 API 时启用了 CORS,并且当时还创建了 OPTIONS 方法。我已尝试根据您的建议更新 OPTIONS 方法标头,但它仍然给出相同的错误。但是当我从浏览器调用 API 时,我只看到 POST 方法而不是 OPTIONS 方法。还好吗? 我还在 POST 请求中看到 403 响应代码,在 Firefox 上带有响应 - "message":"Missing Authentication Token",在 Chrome 上没有响应。我认为这不是身份验证问题,因为我可以在没有令牌的情况下从邮递员访问 API。 我还有一个疑问是,如果我已经在 OPTIONS 方法上启用了 CORS 标头,我是否还必须为同一资源下的 POST 方法添加相同的标头。因为目前,我已经在 OPTIONS 方法上启用了 CORS,并且还从 POST 方法的 Node Js 代码发送标头。 奇怪。您能否发布选项和发布方法的请求方法配置?我会尝试在舞台上启用 CloudWatch 访问日志,然后尝试从浏览器和邮递员访问 API 端点几次,然后发布这些。 我已启用 CloudWatch 日志。问题已解决。以前,我收到了 403 响应代码,因为我使用了不正确的端点。即使在更正它之后,我也收到了 CORS 错误,因为我的服务器端代码没有进行异常处理。出错时,它没有发送 CORS 标头。感谢您的帮助。

以上是关于使用 POST API 时出现多个 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

发出发布请求时出现NodeJS CORS错误

发出 GET 请求时没有 CORS 错误,但发出 POST 请求时出现 CORS 错误

为啥调用 API 时出现 CORS 错误

axios POST 请求到后端时出现 CORS 错误

发出 POST 请求时出现 Google Cloud Function CORS 错误

使用 XHR 请求 API 时出现 CORS 错误