Skip to content

上一篇文章 静态资源服务器,我们通过 mime-types,将原本繁琐的文件类型判断和 MIME 值对应处理地更为健壮,扩展性更强。也已经基本解决了各种静态资源的请求和读取问题。

那么这一章呢,我们来实现一个:接口服务器

回想一下,前后端功能对接,是不是后端提供接口地址,然后前端带上参数请求该地址,拿到返回的数据,并把数据渲染到页面上的呢。

要实现接口的话,其实也非常简单,可以说简单地不像话。请求接口和请求静态资源文件没有什么太大的区别。一个是读取并 返回文件,一个则是 返回JSON数据

js
import { createServer } from 'node:http';
import { readFileSync, existsSync } from 'node:fs';
import { lookup } from 'mime-types';

const server = createServer((req, res) => {
    if (req.url.startsWith('/api/') === true) {
        if (req.url === '/api/getUserScore') {
            res.end({
                code: 0,
                msg: '查询数据成功',
                data: {
                    id: 1,
                    name: 'chensuiyi',
                    score: 100
                }
            });
        }
    } else {
        if (req.url === '/') {
            req.url = '/index.html';
        }
        if (existsSync(`./public/${req.url}`) === true) {
            res.setHeader('Content-Type', lookup(req.url));
            res.end(readFileSync(`./${req.url}`));
        } else {
            res.writeHead(404, { 'Content-Type': 'text/plain' });
            res.end('404 Not Found');
        }
    }
});

server.listen(3000, '127.0.0.1', () => {
    console.log('服务已启动,监听端口为:3000');
});

为了将资源请求和接口请求进行区分,便于我们判断。我们规定,所有的接口请求都必须以 /api/ 为前缀。

凡是请求地址的前缀为 /api/ 的,则进入接口相关的处理逻辑,否则就是资源相关的处理逻辑。

那么,我们也设计一个接口,请求路径是 /api/getUserScore,功能是获取用户分数。

当我们的服务器匹配到这个请求路径的时候,就返回对应的 JSON 数据。

无法访问此页面

服务器启动后,我们在浏览器发起请求。

控制台报错

但是,不光浏览器没拿到数据,连我们的后端程序都崩了。

js
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received an instance of Object

报错内容是这样的,我们分成几段来看。

什么错误呢?TypeError

Type=类型Error=错误,对了,是 类型错误

什么样的类型错误呢?ERR_INVALID_ARG_TYPE

ERR=错误INVALID=无效的ARG=参数TYPE=类型

连起来就是,无效的参数类型

哪个地方出的错呢?D:/codes/nodeFullStack/api/server.js:8:17

server.js 文件的 第8行,这行有个什么函数?res.send()

哦,我明白了,res.send() 函数的参数类型错了。

可我们明明给的是 JSON对象 啊,这个 JSON对象 又没错。

唉,还真是这个 JSON对象 错了,咱们继续往后看。

js
The "chunk" argument must be of type string or an instance of Buffer or Uint8Array.

The “chunk” 就是我们要给 res.send 提供的参数,它的中文含义叫做 ,就是一块一块的,一份一份的意思。

也就是说,我们提供给 res.send() 函数的参数,要一块一块的,一份一份的。

那么什么样的类型,是一块块,一份份的呢?

继续看后面的文字,翻译过来就是 “参数必须是字符串类型,或者是 Buffer,Uint8Array 的实例”

Buffer 和 Unit8Array 看不懂不要紧,一两句话也说不清,购买了本小册的话,可以私聊加我微信 chensuiyime 到问答群交流提问。

那么这个字符串类型,肯定明白吧,问题找到了,res.send() 函数需要字符串类型,而我们给它的确实 JSON对象

那么如何将 JSON 结构变成字符串呢,很简单,JSON.stringify 来帮忙。

js
if (req.url === '/api/getUserScore') {
    res.end({
        code: 0,
        msg: '查询数据成功',
        data: {
            id: 1,
            name: 'chensuiyi',
            score: 100
        }
    });
}

// 以上代码,改成如下

if (req.url === '/api/getUserScore') {
    res.end(
        JSON.string({
            code: 0,
            msg: '查询数据成功',
            data: {
                id: 1,
                name: 'chensuiyi',
                score: 100
            }
        })
    );
}

接口正常返回了

这么一操作,我们就能拿到接口的返回数据了。

但,问题又来了,怎么乱码了?

很简单,还记得前面章节,如何解决乱码问题的吗?

如果忘记了,请看第二章从一个简单的例子开始。

那么我们的解决方法如下:

js
if (req.url === '/api/getUserScore') {
    res.setHeader('Content-Type', 'application/json; charset=utf-8');
    // res.setHeader('Content-Type', 'application/json'); 也可以不加编码,也会正常显示
    res.end(
        JSON.stringify({
            code: 0,
            msg: '查询数据成功',
            data: {
                id: 1,
                name: 'chensuiyi',
                score: 100
            }
        })
    );
}

设置返回头的 Content-Type 属性的值为 application/json

这就等于告诉浏览器:嘿,听好了,我要返回的数据是 JSON 结构,用 UTF-8 编码显示,可别整乱码了

正常显示

这么一来,数据显示就正常了。

头部属性生效了

也可以看到,我们设置的头部 Content-Type 属性也生效了。

那么到了这一步,我们的接口服务器,就算完成了。

what?这就完成了?

没错,完成了。

如果需要增加新的接口,那么增加不同的接口判断就行了。

后续章节,我们会逐步完成接口的功能,比如 读取数据库,实现 登录注册 等等。

但是,这些都是对接口功能的完善,本质上来说,所谓的后端接口,就是判断不同的接口请求,返回不同的数据而已。我们所想象的全栈开发,接口开发好难好难,其实远远没有想象中那么难。

那么我们再回过头思考前面的一个问题,为什么接口不能返回 JSON对象?三秒中思考一下。

OK,这是因为,JSON对象 是一个数据结构,是一个抽象的东西。

你不仅不能返回 JSON对象,也不能返回 Array数组

浏览器和服务器之间的数据交换,交换的是 数据,而不是 结构

我们的上一章静态资源服务器,读取各种文件并进行返回,也不是返回 结构,而是不同文件的 数据

图片有图片的数据,文件有文件的数据,这是实实在在的数据,而不是抽象的结构。

所以呢,我们才需要用到 JSON.stringif y 方法,来把 JSON对象 变成 JSON 字符串 数据。

本章非常重要,理解清楚,可以有效地解决对于全栈开发,接口开发的未知和恐惧,其实也就那样。

那么后续呢,我们进一步完善我们的接口服务器,让其更健壮,更方便,为我们即将到来的实战,个人博客全栈项目开发,打下基础。

何以解忧,唯有代码。不忘初心,方得始终。