Nodejs HTTP Server

背景

最近有一个想法是做一个图片小工具,这个小工具可以给图片提供一些常用或不常用的图片做转换

又一次的 我想到了 cloudflare worker,能白嫖一些计算资源, 可用性又不用担心。(实际上是我想的太美了)。

所以我先想到nodejs上是不是有一些现成的图像处理库,找了一下 还真有 而且API用起来很舒服(Sharp 后续会单开文章来写)。

接下来就需要一个 server 来提供服务,把输入输出都对接好 就完事了。

然而

并不是这么work的。

Cloudflare Worker并不支持Nodejs 只是说恰好支持某些库而已,在这里查找可以在worker上工作的库(实际上我认为就是用了Nodejs但是阉割了非常多的API 防止滥用)

并且 express 也不在支持范围内。虽然给我挖了大坑,但是 探索这件事情本身也非常有意思。

HTTP Module

最开始怎么简单怎么来么,并且我想看看 Nodejs 原生发展的如何

怎么写一个server?

const http = require('http')
// 参数解析
const { URLSearchParams } = require('url');


const port = 8081;


const server = http.createServer()


/**
 * server request 事件处理
 * @param Request 请求对象可以用来获取客户端的一些请求信息,例如请求路径
 * @param Response 响应对象可以用来给客户端发送响应消息
 */
server.on('request', (request, response) => {
    console.log('url: ' + request.url)


    let body = [];
    // https://stackoverflow.com/questions/4295782/how-to-process-post-data-in-node-js
    request.on('data', chunk => body.push(chunk))
        .on('end',() => {
            let buffer = Buffer.concat(body);


            // let urlSearchParams = new URLSearchParams(buffer.toString());


            console.log(buffer.toString('utf8', 0, 200));


            // send response
            response.write('resp over.'); // Can be called multiple times 
            response.end();


        })
});


// start server
server.listen(port, () => {
    console.log(`server start on  http://127.0.0.1:${port}/ `);
})

这里面有一个很有意思的东西, chunk size不固定,且有多次,通过buffer打印出的东西 是这样的

--WebAppBoundary
Content-Disposition: form-data; name="image"; filename="wayne 2022.jpg"
Content-Type: */*; charset=UTF-8
Content-Transfer-Encoding: binary


�����ExifMM*

这是原始未解析的HTTP请求内容。

所以,Spring Web写多了,就非常理所当然的认为 Header,参数的解析都是已经做好的了。

但是,在做应用程序的时候是不能这么原始的来做的。

所以要引入一个web框架,那就是 express

express

https://expressjs.com/

const express = require('express')
const multiparty = require('multiparty');
const cors = require('cors')


const app = express()


// test only
app.use(cors({
    origin: '*'
}))


// post roter
app.post('/api/image/:type', function (req, res) {


    // parse form object
    let form = new multiparty.Form();


    let image = {
        filename: 'untitled.',
        size: 0,
        buffer: []
    };


    form.on('close', () => {
        let buffer Buffer.concat(image.buffer);
        console.log(buffer.toString('utf8', 0, 200));


        res.send('requese received');


    });


    // listen on part event for image file
    form.on('part', part => {
        part.on('data', (buf) => {
            image.size += buf.length;
            image.buffer.push(buf);
        });
    });


    // parse the form
    form.parse(req);
})


// start server
app.listen(8081)
console.log('Express started on port 8081');

看起来虽然步骤差不多,但是express做了很多解析工作,但有没有做很多。

比如 form表单解析,仍然需要一个multiparty组件去解析,cors虽然默认生效,但无法控制,需要再 引入 cors 组件来控制。

这个工作模式 对我来说 我觉得 真的是尽到了职责分明,不会像是SpringWeb一样全部 All in one 粘合在一起。

当然 他们各有各的好处。

itty-router

https://github.com/kwhitley/itty-router

itty router 是我必须要介绍,但是又不需要给出 example 的一个组件,因为在我原始的设计中,应用是需要跑在cloudflare上的,所以要用web框架最好的选择就是这个。当然也可以用在其他嵌入式(类似)project中。

具体的例子清参见 cloudflare/worker-template-router