在html中请求本地json文件的三种方法

引言

在使用D3请求本地json文件的时候出现了跨域问题,探索了下整理了想到的三种解决方法。

一、问题定位

先看下我出问题的程序,这个程序是在html页面中,用d3抓取本地的bar.json 作为数据源,操作dom来用svg绘制柱状图。程序代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<!DOCTYPE html>
<html>

<head>
<title>D3 Page</title>
<script type='text/javascript' src='Scripts/d3.js'></script>
<script type='text/javascript' src='test.js'></script>

<link href="styles/char_6.css" rel="stylesheet">
</head>

<body>
</body>
<script type='text/javascript'>


d3.json('bar.json', function (json) {
return json
}).then(function (json) {
//解析数据
var dataset = json['dataset']
//获取svg画布
var svg = d3.select("body")
.append("svg")
svg.attr("width", 500)
.attr("height", 200);

//保存矩形数组的选择器
var rects = svg.selectAll("rect")
.data(dataset) //匹配
.enter() //选中
.append("rect")

//根据数据设置柱形图的大小
rects.attr("class", "rec")
.attr("x", function (d, i) {
return (i * 20) + 10
})
.attr("y", function (d) {
return (200 - Number(d) * 4).toString()
})
.style('height', function (d) {
return 4 * d + 'px'
})
.attr("fill", function (d) {
return "rgb(0,0," + Math.round(d * 10) + ")";
});

//添加标签
var texts = svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function (d) {
return d;
})
texts.attr("x", function (d, i) {
return (i * 20) + 13
})
.attr("y", function (d) {
return 215 - d * 4;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")


})

</script>

</html>

直接打开html页面,没有效果接着我打开devTools 的控制台一看报了一个跨域错误。抛出了个Fetch API的异常(说明d3.json这个方法底层是调用的Fetch API),显示了一个跨域错误。(关于跨域是什么详情可以看下跨域资源共享-MDN ,跨域资源共享 CORS 详解–阮一峰)也就是说访问本地文件是不被浏览器允许的,那则么解决这个问题呢?

二、解决方法

1. 把json作为一个js的对象引入

因为,json本身就来自于js语法和js相同,所以可以把json内容复制到一个js的对象中,然后把这个js文件引入html页面。

  1. 定义一个js文件
1
2
3
4
5
let aa = {
dataset: [5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25
]
}
  1. 引入到目标html页面
1
<script type='text/javascript' src='test.js'></script>

2. 把html页面运行到一个应用服务器上

直接访问会遇到跨域,那我们可以绕开跨域,把我们的页面和本地文件都放在同一个应用服务器上,不跨域了自然就没有跨域问题了。

  1. 用python3自带的http 服务器
    在命令行输入

    1
    python -m http.server port

    port:端口号 默认是8000 端口,如果你要改再指定。
    详情可以看python的官方文档
    http.server — HTTP 服务器 — Python 3.9.4 文档

  2. 用express.js
    python自带的http服务器性能比较差,如果你经常改动html页面保存,刷新。过段时间会卡主。 可以用node的express.js的静态文件功能。把html页面放到静态文件夹里。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const express = require('express');
    const logger = require('morgan');
    const app = express();
    app.get('/', (req, res) => {
    res.send('Hello World!');
    });
    app.use(logger('dev'))
    app.use(express.static('./'))
    app.listen(3000, () => {
    console.log('示例应用正在监听 3000 端口!');
    });

note: 1. express.static(‘./‘) 这个方法里面 ‘./‘表示的是指定的放静态文件的文件夹。默认是当前根目录下的static目录。

3. 把本地文件放在一个加了跨域头的应用服务器上

上面内个方法是绕过了跨域而这个方法是在服务器端解决了跨域请求(不清楚跨域问题的可以看引言部分我给出的两个链接)

为了访问本地文件,自己写一个处理好跨域请求的服务器有点呆。我们可以用人家现成的工具。我这里用的json-server。json-server是一个基于express.js默认开启跨域的应用服务器,经常被前端用来mock后端请求用。使用的时候只需要一行代码非常方便。 具体用法见npm里的说明npm json-server

1
json-server --watch bar.json

Note: 1.默认的静态文件夹是 static,可以通过命令修改。

总结

本文主要介绍了在html页面中访问本地json文件的三种方法,分别是将json文件变成js对象引入,将html页面放到应用服务器上,将本地文件放到处理了跨域请求的应用服务器上。如果不是在html页面中用的话,其实还可以用node的fs模块。