本地打开D3 HTML文件遇跨域及报错不一致问题求助
一、跨域错误的原因
直接用Chrome打开本地HTML文件时,浏览器使用的是file://协议,而Chrome默认禁止该协议下的跨域资源请求(比如加载本地的data.csv)。而Python本地服务器用的是http://协议,符合浏览器的跨域规则,所以不会报错。
二、报错位置不一致的本质
两种场景触发了不同的错误路径:
- 直接打开时:浏览器阻止了
data.csv的加载,导致d3.csv回调里的d是null,执行d.forEach时直接抛出错误,对应第32行; - 用服务器打开时:
data.csv正常加载,代码执行到后面遇到了.calls这个不存在的方法(正确的是.call),所以报错在第59行。
简单说就是,前者在数据加载阶段就失败了,后者走到了后续代码才出错,所以报错行号不同。
三、你的Sublime构建系统是否可靠?
这个构建系统本身没问题,但它解决不了Chrome对file://协议的限制。如果你的D3代码不需要加载本地外部资源(比如CSV、JSON),它可以正常用;但只要涉及本地数据读取,就会触发跨域错误,所以不适合你的开发场景。
四、无需本地服务器打开的可行方案
这里有几个实用的方法:
修改Chrome启动参数
给Chrome添加允许本地文件访问的参数,修改你的Sublime构建系统为:{ "cmd": ["C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", "--allow-file-access-from-files", "$file"] }注意:这个参数会降低浏览器的安全性,仅在开发时使用,用完请关闭Chrome再正常启动(不带该参数)。
内嵌数据到代码中
把data.csv的内容转换成JSON格式,直接写在JS代码里,比如:// 替换原来的d3.csv调用 var d = [ {time: "2000", value: 123, gdp_per_capita: 45678}, {time: "2001", value: 456, gdp_per_capita: 56789}, // 其他数据行... ]; // 后面直接处理这个d数组即可这样就不需要加载外部文件,自然不会有跨域问题。
改用Firefox浏览器
Firefox对本地文件的跨域限制比Chrome宽松很多,直接用Firefox打开你的HTML文件,通常能正常加载本地CSV,不需要额外设置。
五、你的D3代码必须修复的两个bug
不管用哪种方式运行,先把代码里的错误修正:
d3.csv的回调参数错误d3.csv的第一个回调参数是错误对象,第二个才是数据数组,你现在的写法会把错误对象当成数据处理,改成:d3.csv("data.csv", function(error, d) { if (error) throw error; // 先捕获加载错误 d.forEach(function(item) { item.date = parseTime(item.time); item.value = +item.value; item.gdp = +item.gdp_per_capita; }); // 后续的比例尺、绘图代码不变 });错误的
.calls方法
D3中没有.calls这个方法,正确的是.call,把第59行和第64行的.calls改成.call:// 左轴 svg.append('g') .attr('class', 'axisLeft') .call(d3.axisLeft(yScale1)); // 右轴 svg.append('g') .attr('class', 'axisRight') .attr('transform', 'translate(' + w + ', 0)') .call(d3.axisRight(yScale2));
内容的提问来源于stack exchange,提问作者Brian

