mcpField
B
bun-http-server

bun-http-server

github.com/secondsky开发240407 次安装5 周前更新
代码仓库

关于 bun-http-server

bun-http-server 是使用 Bun 构建 HTTP 服务的技能,面向开发者介绍请求处理、路由、响应类型、静态文件、CORS 和服务配置。

主要功能

  1. 01使用 Bun.serve() 创建服务
  2. 02处理请求方法和请求体
  3. 03定义路由与动态参数
  4. 04返回 JSON 等响应
  5. 05提供静态文件
  6. 06配置 TLS 和 CORS

适用场景

  1. 01构建轻量 HTTP API
  2. 02解析 JSON 或表单提交
  3. 03提供静态资源
  4. 04配置 HTTPS 或流式响应

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/secondsky/claude-skills --skill bun-http-server

安装后在 Claude Code 中输入/bun-http-server确认已加载。

详细介绍

Bun HTTP 服务

Bun 通过 Bun.serve() 内置了高性能 HTTP 服务。

快速入门

const server = Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response("Hello World!");
  },
});

console.log(`Server running at http://localhost:${server.port}`);

请求处理

Bun.serve({
  fetch(req) {
    const url = new URL(req.url);

    // Method
    console.log(req.method); // GET, POST, etc.

    // Path
    console.log(url.pathname); // /api/users

    // Query params
    console.log(url.searchParams.get("id")); // ?id=123

    // Headers
    console.log(req.headers.get("Content-Type"));

    return new Response("OK");
  },
});

请求体解析

Bun.serve({
  async fetch(req) {
    // JSON
    const json = await req.json();

    // Form data
    const form = await req.formData();

    // Text
    const text = await req.text();

    // ArrayBuffer
    const buffer = await req.arrayBuffer();

    // Blob
    const blob = await req.blob();

    return new Response("Received");
  },
});

响应类型

Bun.serve({
  fetch(req) {
    const url = new URL(req.url);

    switch (url.pathname) {
      case "/json":
        return Response.json({ message: "Hello" });

      case "/html":
        return new Response("<h1>Hello</h1>", {
          headers: { "Content-Type": "text/html" },
        });

      case "/redirect":
        return Response.redirect("/new-location", 302);

      case "/file":
        return new Response(Bun.file("./image.png"));

      case "/stream":
        return new Response(
          new ReadableStream({
            start(controller) {
              controller.enqueue("chunk1");
              controller.enqueue("chunk2");
              controller.close();
            },
          })
        );

      default:
        return new Response("Not Found", { status: 404 });
    }
  },
});

简单路由

Bun.serve({
  fetch(req) {
    const url = new URL(req.url);
    const path = url.pathname;
    const method = req.method;

    // Static routes
    if (method === "GET" && path === "/") {
      return new Response("Home");
    }

    if (method === "GET" && path === "/api/users") {
      return Response.json([{ id: 1, name: "Alice" }]);
    }

    // Dynamic routes
    const userMatch = path.match(/^\/api\/users\/(\d+)$/);
    if (method === "GET" && userMatch) {
      const userId = userMatch[1];
      return Response.json({ id: userId });
    }

    // 404
    return new Response("Not Found", { status: 404 });
  },
});

错误处理

Bun.serve({
  fetch(req) {
    try {
      // Handle request
      throw new Error("Something went wrong");
    } catch (error) {
      return new Response(
        JSON.stringify({ error: error.message }),
        {
          status: 500,
          headers: { "Content-Type": "application/json" }
        }
      );
    }
  },
  error(error) {
    // Global error handler
    return new Response(`Error: ${error.message}`, { status: 500 });
  },
});

服务选项

const server = Bun.serve({
  port: 3000,           // Default: 3000
  hostname: "0.0.0.0",  // Default: "0.0.0.0"

  development: true,    // Pretty errors in browser

  // TLS/HTTPS
  tls: {
    key: Bun.file("./key.pem"),
    cert: Bun.file("./cert.pem"),
  },

  // Unix socket
  unix: "/tmp/my-socket.sock",

  // Max request body size (default 128MB)
  maxRequestBodySize: 1024 * 1024 * 10, // 10MB

  fetch(req) {
    return new Response("OK");
  },
});

服务方法

const server = Bun.serve({ ... });

// Server info
console.log(server.port);        // 3000
console.log(server.hostname);    // "0.0.0.0"
console.log(server.url);         // URL object

// Stop server (Bun 1.2+: returns a Promise — await it to flush in-flight
// requests; calling it without await may not drain connections).
await server.stop();

// Reload with new config
server.reload({
  fetch(req) {
    return new Response("Updated!");
  },
});

// Pending requests count
console.log(server.pendingRequests);

使用 routes 进行路由(Bun 1.2+)

上面的示例使用经典的 fetch(req) 处理程序手动解析 URL,这种方式仍然可用。从 Bun 1.2 开始,声明路由映射的标准方式是使用 routes 选项,动态参数可通过 req.params 获取:

Bun.serve({
  routes: {
    "/api/users": {
      GET: () => Response.json([{ id: 1, name: "Alice" }]),
      POST: async (req) => Response.json(await req.json(), { status: 201 }),
    },
    "/api/users/:id": (req) => {
      const { id } = req.params;
      return Response.json({ id });
    },
  },
  fetch(req) {
    return new Response("Not Found", { status: 404 });
  },
});

新代码请使用 routes;将 fetch 保留为未匹配路径的回退处理方式。

静态文件

Bun.serve({
  fetch(req) {
    const url = new URL(req.url);

    // Serve static files from public/
    if (url.pathname.startsWith("/static/")) {
      const filePath = `./public${url.pathname.replace("/static", "")}`;
      const file = Bun.file(filePath);

      if (await file.exists()) {
        return new Response(file);
      }
      return new Response("Not Found", { status: 404 });
    }

    return new Response("API");
  },
});

CORS

function corsHeaders() {
  return {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
    "Access-Control-Allow-Headers": "Content-Type, Authorization",
  };
}

Bun.serve({
  fetch(req) {
    // Handle preflight
    if (req.method === "OPTIONS") {
      return new Response(null, { headers: corsHeaders() });
    }

    // Add CORS headers to response
    return new Response("OK", { headers: corsHeaders() });
  },
});

常见错误

错误原因修复方法
EADDRINUSE端口已被占用使用其他端口或终止相关进程
Cannot read body请求体已被读取只读取一次请求体
CORS error缺少标头添加 CORS 标头
413 Payload Too Large请求体超出限制增大 maxRequestBodySize

何时加载参考资料

在以下情况下加载 references/tls-config.md:

  • HTTPS/TLS 设置
  • 证书配置
  • mTLS 身份验证

在以下情况下加载 references/streaming.md:

  • 服务器发送事件
  • 流式响应
  • 分块传输编码

评论

支持 Markdown