Posts
Create Server-Sent Events in Nextjs

由于Nextjs新的 App Router 采用的是 Mozilla 标准 WebAPI 的 Response, 所以写法和普通的 Node SSE 略有不同。
以下是代码示例:

服务端 app/api/stream/route.ts

import { NextRequest, NextResponse } from 'next/server'

export async function GET(request: NextRequest) {
    const sseData = `:ok\n\nevent: message\ndata: Initial message\n\n`
    // 将 SSE 数据编码为 Uint8Array
    const encoder = new TextEncoder()
    const sseUint8Array = encoder.encode(sseData)

    // 创建 TransformStream
    const transformStream = new TransformStream({
        transform(chunk, controller) {
            controller.enqueue(chunk)
        },
    })

    // 创建 SSE 响应
    let response = new Response(transformStream.readable)

    // 设置响应头,指定使用 SSE
    response.headers.set('Content-Type', 'text/event-stream')
    response.headers.set('Cache-Control', 'no-cache')
    response.headers.set('Connection', 'keep-alive')
    response.headers.set('Transfer-Encoding', 'chunked')

    const writer = transformStream.writable.getWriter()
    writer.write(sseUint8Array)

    // 定义一个计数器
    let counter = 0

    // 每秒发送一个消息
    const interval = setInterval(() => {
        counter++

        if (counter > 10) {
            clearInterval(interval)
            return
        }

        const message = `event: message\ndata: Message ${counter}\n\n`
        const messageUint8Array = encoder.encode(message)
        writer.write(messageUint8Array)
    }, 1000)

    return response
}


客户端

const eventSource = new EventSource('/sse/api/stream')
// 监听 SSE 事件的消息
eventSource.onmessage = function (event) {
    console.log('Received message:', event.data)
}


但是常规的 SSE 只可以通过GET来访问,这就导致请求方传递参数会有一些不那么优雅。如果需要传递大量文本时无法满足。

我们可以使用 Azure 的 fetch-event-source

在 Nextjs 中,服务端仅需将 GET 方法名改为 POST

客户端的修改如下:

import { fetchEventSource } from '@microsoft/fetch-event-source';
const eventSourcePost = fetchEventSource('/sse/api/stream', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        foo: 'bar'
    }),
    onmessage: function (event) {
        console.log('Received message:', event.data)
    }
});
Add GCC for node-canvas in Centos7.x

Node环境做canvas绘画时,依赖CXXABI_1.3.9,但目前有一些centOS7的环境本身并不带此依赖。 在常规服务器上,我们只需要手动安装即可。但如果是通过ci/cd做镜像部署的时候,需要在项目中添加postinstall来实现。

问题描述:

Error: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found

centos7.x 缺少 CXXABI_1.3.9


解决方案:

  1. package依赖canvas版本在2.8以上
  2. 新增npm script:
    "postinstall": "yum install -y gcc-c++ cairo-devel libjpeg-turbo-devel pango-devel giflib-devel librsvg2-devel build && npm rebuild canvas --build-from-source"
    
  3. 项目 script 文件夹下新增 image_hook.sh:
    yum install -y cairo-devel libjpeg-turbo-devel pango-devel giflib-devel librsvg2-devel
    


TODO

另外这里还有一个问题,由于yum本身在 Windows/Mac 并不存在,因此在postinstall时需要考虑判断操作系统。


相关问题

Cannot get canvas running on CentOS 7


How to use patch-package

patch-package 允许在不修改原始依赖包源代码的情况下,对其进行补丁修复。

安装 patch-package

npm install patch-package --save-dev

在项目的根目录下创建一个名为patches的文件夹

mkdir patches

在patches文件夹下创建一个与text-svg包对应的补丁文件,文件名的格式通常是package-name.patch,其中package-name是第三方包的名称。 比如这里需要修改text-svg 这个包的 dependencies,所以创建一个text-svg.patch文件

--- a/node_modules/text-svg/package.json
+++ b/node_modules/text-svg/package.json
@@ -18,7 +18,7 @@
  "dependencies": {
    "canvas": "1.0.6"
  },
-  "optionalDependencies": {
+  "optionalDependencies": { }

在这个补丁文件中,修改了text-svg包的package.json文件,将其canvas的依赖版本从1.0.7改为1.0.6。另外,我们将optionalDependencies字段设置为空对象,以确保不会影响到其他依赖项。

运行以下命令来应用补丁:

npx patch-package text-svg

为了确保其他人克隆你的项目时也能自动应用这些补丁,将生成的补丁文件添加到你的版本控制系统中,并将其提交到代码库中。 在项目中创建postinstall脚本,以便在每次安装依赖时自动应用补丁。

#!/bin/sh

# Apply patch-package patches after npm install
npx patch-package

这段脚本会在每次运行npm i(或npm install)时自动调用patch-package命令来应用补丁。

在package.json文件中的scripts字段中添加一个postinstall脚本,指向你刚创建的postinstall文件:

"scripts": {
  "postinstall": "./postinstall"
}

并且确保你的package.json文件中包含了patch-package作为开发依赖项:

"devDependencies": {
  "patch-package": "^X.X.X"
}

这样,当其他人克隆你的项目并运行npm i时,postinstall脚本会自动调用patch-package命令,并应用你提交的补丁文件。