Hapi、Joi 和 Formdata 上传出现神秘的间歇性 CORS 错误

Posted

技术标签:

【中文标题】Hapi、Joi 和 Formdata 上传出现神秘的间歇性 CORS 错误【英文标题】:Mystery intermittent CORS error with Hapi, Joi, and Formdata uploads 【发布时间】:2021-11-10 01:51:06 【问题描述】:

我已经调试了几天,我希望你们中的一个优秀的人之前遇到过类似的事情,并且对我们有一些想法。

MacOS 大苏尔, 客户端和 API 都是 javascript, 反应/Node.js, 哈皮/乔伊,

问题如下:某些 PDF/图像将无法上传到我们的 REST API。从来没有在 Safari 中,有时在 Firefox 中,总是在 Chrome 和 Edge 中。

API 部署到 AWS,当运行我们的本地实例时,我们无法重现此问题(当然,上传在本地永远不会失败,没有调用 CORS。本地环境与部署的环境相同)。

上传请求在使用某些文件时会一直失败,而在使用其他文件时会一直正常工作,就好像文件本身已损坏一样。例如,PDF-A 总是会失败(除非在本地发送,否则它会工作。我们在本地的 API 代码中没有失败或错误),PDF-B 永远不会失败。

我们收到这个经典错误(在 Edge 和 Chrome 中一致,在 Firefox 中是间歇性的,在 Safari 中不存在):

CORS 策略已阻止从源“http://localhost:3000”获取“https://apiUrl/relevant-endpoint”的访问权限:没有“Access-Control-Allow-Origin”标头存在于请求的资源上。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

我们在 API 中处理 CORS,通过动态返回预检请求信息:

if (request.method === 'options') 
            response.statusCode = 200;
            response.headers['access-control-expose-headers'] = 'content-type, content-length, etag';
            response.headers['access-control-max-age'] = 60 * 10; // 10 minutes

            // dynamically set allowed headers & method
            if (request.headers['access-control-request-headers']) 
                response.headers['access-control-allow-headers'] = request.headers['access-control-request-headers'];
            

            if (request.headers['access-control-request-method']) 
                response.headers['access-control-allow-methods'] = request.headers['access-control-request-method'];
            

     return h.continue;

它已经投入生产 2 年,已经处理了几千个成功的文件上传,成千上万的请求。

我们的客户端请求如下:

function request(req) 
    return new Promise((resolve, reject) => 
        const endpoint = `$ apiUrl $ req.endpoint `;

        const options = 
            method: req.method.toUpperCase()
        ;

        fetch(endpoint, options)
            .then((res) => res.json())
            .then((res) => 
                if (res.status === 'Fail') 
                    reject(res);
                 else 
                    resolve(res.data);
                
            )
            .catch((err) => 
                reject(err);
            );
);

function submit(body) 
    const options = 
        endpoint: '/relevant-endpoint',
        method: 'POST',
        body
    ;

    // Body : FormData  ... 

    return new Promise((resolve, reject) => 
        request(options)
            .then(resolve)
            .catch(reject);
    );


const form = new FormData();

form.append('string A', this.state.stringA);
form.append('string B', this.state.stringB);
form.append('string C', this.state.stringC);
form.append('int A', this.state.intA);
form.append('file A', this.state.fileA); // the culprit
form.append('date A', this.state.dateA));

submit(form);

如果导致错误的文件被优化,对于 jpeg/png,或在 PDF 的情况下被编辑(即,在 Adob​​e 中删除的字体),它们将成功上传。我无法确切地发现导致文件失败的特征。我们能够成功提交更大或更小的文件,并且如前所述,有些文件具有相同的内容。

如有必要,我可以添加一些额外的服务器端逻辑,但我不确定问题是否与此有关。

【问题讨论】:

【参考方案1】:

对于将来阅读本文的任何人,我们今天的实施取得了一些进展,但我们还没有更深入地了解这个错误。

我们有另一个文件上传部分,可以将类似文件 (new Formdata(), form.append()) 作为数组发送。我们发现,当我们在第二个位置发送通常会触发 CORS 错误的文件时,它不会触发错误。

所以现在我们发送[ null, file ]。如果我们发送[ file ][ file, null ] 它仍然会触发错误。我希望这对任何人都有帮助,或者如果您对我们有进一步的了解,我期待了解这里到底发生了什么。谢谢!

【讨论】:

以上是关于Hapi、Joi 和 Formdata 上传出现神秘的间歇性 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

hapi route joi 验证密码确认

[Hapi.js] Request Validation with Joi

我看hapi

知名Node.js框架系列之:我看hapi(哈啤)

关于EGG项目添加Joi参数校验解决方案

Joi 验证器条件模式