向 Google 表格提交表单时出错,导致 CORS 错误

Posted

技术标签:

【中文标题】向 Google 表格提交表单时出错,导致 CORS 错误【英文标题】:Error submitting form to Google Sheets which causes a CORS error 【发布时间】:2021-07-07 05:02:17 【问题描述】:

我目前有一个在 localhost 上运行的表单,该表单将数据提交到 Google 表格的脚本以将其发布到电子表格中。每次我提交表单时,我都会收到此错误: 跨域请求被阻止:同源策略不允许在 https://script.google.com/macros/s/xxxxxxxxx/exec 读取远程资源。 (原因:CORS 标头“Access-Control-Allow-Origin”缺失)

在 Google 脚本方面,我已经将部署设置为:执行设置为 Me,谁有权访问设置为 Anyone

这是用于提交表单的 javascript 代码。

form.addEventListener('submit', (e) => 
    e.preventDefault();
    console.log("form has been submitted!");
    fetch('https://script.google.com/macros/s/xxxxxxxxx/exec',  
        method: 'POST', 
        mode: 'cors',
        body: new FormData(form)
    )
        .then(response => 
            if(response.ok) 
                console.log('Success!', response);
             else 
                console.log(response);
                alert("Ohhh noooo!! ERROR please try again response: " + response.status);
            
        )
        .catch(error => 
            console.log("Error!!" + error);
            console.error('Error!', error.message);
            alert('BEEP BOOP: there is an error, please try again');
        );

这是 Google 表格的脚本

function intialSetup() 
    var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
    scriptProp.setProperty('key', activeSpreadsheet.getId());


function doPost(e) 
    var lock = LockService.getScriptLock();
    lock.tryLock(10000);

    try 
        var doc = SpreadsheetApp.openById(scriptProp.getProperty('key'));
        var sheet = doc.getSheetByName(sheetName);

        var json = JSON.stringify(e.postData);
        var obj = JSON.parse(json);
        var task = obj["task"];

        // spreadsheet tab names
        switch (task) 
            case "Tech Trimming":
                specificTab(task, obj["tray_number"], obj["name"], obj["qrCodeArea"].split("\n"));
                break;
            default:
                Logger.log("option does not exist");
        

        return ContentService
            .createTextOutput(JSON.stringify( 'result': 'success', 'row': nextRow ))
            .setMimeType(ContentService.MimeType.JSON)
    

    catch (e) 
        return ContentService
            .createTextOutput(JSON.stringify( 'result': 'error', 'error': e ))
            .setMimeType(ContentService.MimeType.JSON)
    

    finally 
        lock.releaseLock();
    



function specificTab(task, trayNum, techName, impressions) 
    var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
    var subSheetName = spreadSheet.getSheetByName(task);

    var date = getDate();
    var lastRow = subSheetName.getLastRow();

    for (var i = 0; i < impressions.length - 1; i++) 
        subSheetName.getRange(lastRow + 1, 1).setValue(date);
        subSheetName.getRange(lastRow + 1, 2).setValue(trayNum);
        subSheetName.getRange(lastRow + 1, 3).setValue(techName);
        subSheetName.getRange(lastRow + 1, 4).setValue(impressions[i]);

        lastRow++;
    

在 Google Scripts 的执行选项卡上,如果您提交,所有执行都会显示为失败

几个月前,在我的另一台计算机上,一切似乎都运行良好。正如我可以提交表格,然后它会毫无问题地发布到电子表格中。我目前使用的计算机似乎给了我这些问题。我无法测试这个理论,因为我现在没有另一台电脑。

我已将此表单部署到 vercel,但似乎没有解决问题。

【问题讨论】:

【参考方案1】:

完全使用纯文本进行通信以避免 CORS 错误

这意味着每当您向网络应用程序发送 POST 请求时,JSON.stringify() 您的所有数据,然后是 JSON.parse()(如果相关)。您可能还需要将标题设置为"Content-Type": "text/plain"

也就是说,不要直接发送FormData对象,确保客户端和Web应用程序之间的所有通信都以纯文本进行,然后在另一端解码信息。

在 Apps 脚本方面,确保您使用的是:

ContentService.createTextOutput(JSON.stringify( 'result': 'success', 'row': nextRow ));
.setMimeType(ContentService.MimeType.TEXT) // Maybe you can omit this line.

而不是:

ContentService.createTextOutput(JSON.stringify( 'result': 'success', 'row': nextRow ));
.setMimeType(ContentService.MimeType.JSON)

回复您的doPost。最好也使用doGet 来执行此操作。

no-cors

如果不需要来自 POST 请求的响应(尽管我想您会想要它),您可以将请求模式设置为 mode: 'no-cors',但是您的客户端将无法访问有关响应的任何信息。

CORS 代理

您还可以设置(或使用第三方服务)代理服务器,该服务器将在后端发出请求,并允许向您的客户端发出 CORS 请求。

参考

Content Service

【讨论】:

这成功了!非常感谢你。您关于 CORS 的建议解决了我的问题。我现在需要修改我的脚本端以解析文本以使其再次按预期工作。

以上是关于向 Google 表格提交表单时出错,导致 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Google 表单/表格中编辑表单提交的响应?

在 Google Apps 脚本中提交 HTML 表单时如何发送地理定位和输入

Rails,如何从控制器提交 PayPal 请求,而不是表单,URL 编码

在不提交表单的情况下触发 Google 脚本

Ajax 表单在应该提交新信息时向数据库提交相同的信息

当用户双击提交按钮时,需要避免向服务器提交两次表单