Node-RED 使用实例,拖拉拽生成对外服务

Node-RED 是一种编程工具,用于以新颖有趣的方式将硬件设备、API 和在线服务连接在一起。

它提供了一个基于浏览器的编辑器,可以使用调色板中的各种节点轻松地将流连接在一起,只需单击一下即可部署到其运行时。

——这是官网的说法,不过即使你的工作和物联网、硬件设备毫不相关,也可以从流程编排中受益。

你可以仅使用 Node-RED 连接各种各样的数据源,并将其转换为对外开放的在线服务。

下面将介绍几个应用实例。

获取 bingimg 网站图片列表,并生成对外 API

bingimg 是一个必应壁纸采集站,网站本身没有提供对外服务的 API。

图片.png

[

    {

        "id": "d75decd7ba414ab0",
        "type": "tab",

        "label": "爬取bingimg网站图片列表",
        "disabled": false,

        "info": "",

        "env": []

    },

    {

        "id": "3d950cd634058fc9",
        "type": "http in",
        "z": "d75decd7ba414ab0",
        "name": "",
        "url": "/api/bingimg",
        "method": "get",
        "upload": false,
        "swaggerDoc": "",
        "x": 100,
        "y": 80,
        "wires": [
            [
                "5b8537791d63163c"
            ]
        ]
    },
    {
        "id": "1c53ec3ffa6ae53d",
        "type": "function",
        "z": "d75decd7ba414ab0",
        "name": "解析并转换消息",
        "func": "const $ = cheerio.load(msg.payload);\n\nconst getPagination = () => {\n    const pagination = $('ul.pagination')\n    const curPage = parseInt(pagination.find('li.active a').text())\n    const totalPage = parseInt(pagination.find('li').eq(pagination.find('li').length - 4).text())\n\n    return {\n        curPage, totalPage\n    }\n}\n\nconst getThumbnail = (item) => {\n    const node = $(item)\n    const imgs = node.find('.card_date_div a')\n\n    return {\n        title: node.find('.card_title').text().trim(),\n        subTitle: node.find('.card_subtitle').text().trim(),\n        publishDate: node.find('.card_date_div .card_foot').eq(0).text(),\n        url: {\n            HD: imgs.eq(0).attr()?.href,\n            UHD: imgs.eq(1).attr()?.href\n        }\n    }\n}\n\nconst data = Array.from($('.thumbnail')).map(getThumbnail)\nconst { curPage, pageSize, totalPage } = getPagination()\n\nmsg.payload = {\n    data,\n    curPage,\n    pageSize,\n    totalPage\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [
            {
                "var": "cheerio",
                "module": "cheerio"
            }
        ],
        "x": 420,
        "y": 80,
        "wires": [
            [
                "29f1f02a71644ca5"
            ]
        ]
    },
    {
        "id": "6344f3ed693ad033",
        "type": "http request",
        "z": "d75decd7ba414ab0",
        "name": "调用 bingimg 服务",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "https://www.bingimg.cn/list{{{id}}}",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 350,
        "y": 180,
        "wires": [
            [
                "1c53ec3ffa6ae53d",
                "7c945d9983f3957f"
            ]
        ]
    },
    {
        "id": "29f1f02a71644ca5",
        "type": "http response",
        "z": "d75decd7ba414ab0",
        "name": "",
        "statusCode": "200",
        "headers": {},
        "x": 600,
        "y": 80,
        "wires": []
    },
    {
        "id": "5b8537791d63163c",
        "type": "change",
        "z": "d75decd7ba414ab0",
        "name": "设置请求参数",
        "rules": [
            {
                "t": "move",
                "p": "req.query.curPage",
                "pt": "msg",
                "to": "id",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 140,
        "y": 180,
        "wires": [
            [
                "6344f3ed693ad033"
            ]
        ]
    },
    {
        "id": "7c945d9983f3957f",
        "type": "debug",
        "z": "d75decd7ba414ab0",
        "name": "debug 1",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 540,
        "y": 260,
        "wires": []
    }
]

使用上面的编排流程,就生成了一个 API,这个 API 的调用详情如下:

图片.png

在这个过程中,我们使用了五个节点来完成了这件事:
首先是 http in 节点,配置了 API 的请求方式和 URL。

图片.png

这样可以使用 GET 请求访问 /api/bingimg 来获取数据。

之后使用 change 节点获取到调用接口传入的 curPage 参数。参数在 msg.query 下面,转换成 msg.id,给后续节点使用

图片.png

配合后续 http request 节点,使用插值的方式获取上一步传入的 msg.id

图片.png
这一步请求 bingimg 的网页,将响应内容原样传递到下一个节点处理

图片.png
下一步是 function 节点,用来处理上一步请求 bingimg 返回的网页数据。

返回的网页是 html,我们使用 cheerio 来解析网页,提取需要的信息。

得益于 Node-RED 基于 Node.js 平台,npm 上面支持 Node.js 的包都可以使用。

在 function 节点中,可以在 Setup 下面指定外部的 node 包,只需要如图配置 cheerio,就可以在函数中用类似 jQuery 的方式提取数据。

图片.png

在 Setup 中指定的包,可以直接使用,无需 require

图片.png
处理之后的值放到 msg.payload 中,直接交给最后的 response 节点

图片.png
在 response 节点中设置响应状态码即可。
跨域等响应也可以在这里配置。

定时推送消息

这里实现了一个简易的 websocket 推送消息接口。每 5s 调用一次 hitokoto 接口,获取消息后推送到 websocket 通道,订阅用户就可即时收到消息。

图片.png

[

    {

        "id": "187ddef186859e69",
        "type": "tab",

        "label": "定时推送消息",
        "disabled": false,

        "info": "",

        "env": []

    },

    {

        "id": "16581924dcbb397b",
        "type": "inject",
        "z": "187ddef186859e69",
        "name": "触发定时任务",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "5",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 120,
        "y": 40,
        "wires": [
            [
                "e03649ad2bb10481"
            ]
        ]
    },
    {
        "id": "96acd12dd0d087c4",
        "type": "websocket out",
        "z": "187ddef186859e69",
        "name": "推送消息",
        "server": "0adc9c4d5e53170b",
        "client": "",
        "x": 600,
        "y": 60,
        "wires": []
    },
    {
        "id": "e03649ad2bb10481",
        "type": "http request",
        "z": "187ddef186859e69",
        "name": "",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "https://v1.hitokoto.cn/?c=a",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 220,
        "y": 120,
        "wires": [
            [
                "3a8f6b0d08c5b777"
            ]
        ]
    },
    {
        "id": "3a8f6b0d08c5b777",
        "type": "function",
        "z": "187ddef186859e69",
        "name": "转换成一句话",
        "func": "const message = msg.payload.hitokoto.trim()\nconst source = msg.payload.from.trim()\n\nmsg.payload = `${message} ——${source}`\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 440,
        "y": 140,
        "wires": [
            [
                "96acd12dd0d087c4"
            ]
        ]
    },
    {
        "id": "0adc9c4d5e53170b",
        "type": "websocket-listener",
        "path": "/ws/greeting",
        "wholemsg": "false"
    }
]

流程如上,使用了 inject、request、function、websocket out 节点完成了这个任务。

图片.png

inject 节点用来手动或定期将消息注入流中。在这里配置了每隔 5s 周期性执行任务。

后面连接 request 节点调用 hitokoto 服务

图片.png
调用服务返回的内容在 function 中处理成一句话

图片.png

最后使用 websocket out 节点配置输出

图片.png

配置完成后,可以创建 websocket 订阅。下面是最终效果,通过使用 在线调试工具 呈现

图片.png

还有更多

上面展示了 Rest API 服务和定时推送两种方式。除了这两种情况外,借助流程编排和内置节点,还可以用作BFF、接口自动化测试等场景。配合其他服务,甚至可以实现每天给女朋友发早安晚安等功能(笑)。

在开发上面示例的过程中,第三方接口的返回结果,我如何能看到?这就涉及到了调试。

如何调试节点?

在预设节点列表中,有一个 debug 节点,可以连接到任意一个想要观察的节点后面

图片.png

debug 节点可以指定将信息输出到调试窗口、控制台等地

图片.png

配置为调试窗口后,一旦执行到这个节点,就会展示在右侧

图片.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYXcYFpX' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片