Apps Script加载Google Drive CSV文件被CORS策略拦截问题
需要基于Google Sheet生成D3.js树形图,参考示例通过CSV文件完成树形图渲染,因此先通过Apps Script将Google Sheet数据导出为CSV存储在Google Drive中,随后参照示例编写代码加载CSV。
加载GitHub托管CSV的可正常运行代码如下:
<script src="https://d3js.org/d3.v4.js"></script> <script> d3.csv('https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/data_hierarchy_1level.csv', function(data) {console.log(data)}) </script>
替换为个人Google Drive中存储的CSV文件地址后,代码如下:
<script src="https://d3js.org/d3.v4.js"></script> <script> d3.csv('https://drive.google.com/uc?id=1S9_KA87o_i7PjHILicXX21mlVeQc1jIA', function(data) {console.log(data)}) </script>
运行后控制台抛出两类报错:
- 跨域拦截:源站对Google Drive文件地址的XMLHttpRequest访问被CORS策略拦截,请求的资源未携带
Access-Control-Allow-Origin响应头。 - 请求失败:GET请求返回
net::ERR_FAILED 303状态码。
已核对两份CSV文件内容完全一致,需要找到可正常加载Google Drive存储文件的方案,使其和普通公网URL资源一样可被前端直接请求。
使用的Google Drive默认uc?id=链接是文件下载/预览跳转地址,并非静态资源直连地址:
- 该地址会返回303重定向,跳转到需要用户身份校验的资源节点
- 响应头默认不配置跨域允许字段,浏览器出于安全策略会拦截前端脚本发起的跨域请求,和CSV文件本身内容无关
以下三种方案均可实现需求,可根据自己的场景选择:
方案1:小文件直连(仅适合10MB以内CSV)
右键点击Drive中的CSV文件,打开共享设置,将通用访问权限修改为「任何人(拥有链接)可查看」并保存。将请求链接替换为带导出参数的直连格式,替换其中的文件ID为你的CSV实际ID即可:https://drive.google.com/uc?export=download&id=你的文件ID&confirm=no_antivirus注意:文件体积过大会触发Google Drive的病毒扫描拦截页,依然会导致跨域报错
方案2:通过Apps Script部署CSV接口(最稳定,无文件大小限制)
既然已经在使用Apps Script处理表格数据,不需要额外将CSV存储到Drive,直接部署一个公开的CSV接口即可,天然支持跨域访问:- 在Apps Script项目中编写如下
doGet函数,替换工作表名称为实际存储树形图数据的表名:function doGet() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("你的数据表名称"); const rows = sheet.getDataRange().getValues(); // 表格数据转CSV格式,兼容单元格内含逗号、引号的场景 const csv = rows.map(row => row.map(cell => `"${String(cell).replaceAll('"', '""')}"`).join(",")).join("\n"); return ContentService.createTextOutput(csv).setMimeType(ContentService.MimeType.CSV); } - 点击右上角「部署」-「新建部署」,类型选择「Web 应用」,将访问权限设置为「任何人」,完成部署后复制生成的Web App URL
- 将该URL直接传入
d3.csv()即可正常加载数据,不会触发跨域问题
- 在Apps Script项目中编写如下
方案3:直接发布Google Sheet为公开CSV
打开存储数据的Google Sheet,点击顶部菜单栏「文件」-「共享」-「发布到网页」,选择对应工作表,发布格式选择「逗号分隔值(.csv)」,点击发布后获取生成的公开链接,该链接支持跨域访问,可直接作为d3.csv的请求地址。如果表格数据更新,发布的CSV内容会自动同步,不需要手动导出文件。
内容的提问来源于stack exchange,提问作者user2964288

