Skip to content

Commit adfa1c3

Browse files
author
CodeBuddy Attribution Bot
committed
fix(attribution): Skill 文档未清晰说明 HTTP 云函数的代码编写规范 (issue_mns1xuxr_arrdn2)
1 parent 9765779 commit adfa1c3

1 file changed

Lines changed: 123 additions & 28 deletions

File tree

config/source/skills/cloud-functions/references/http-functions.md

Lines changed: 123 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ HTTP Functions are standard web services, not `exports.main(event, context)` han
1010
- Listen on port `9000`.
1111
- Ship an executable `scf_bootstrap` file.
1212
- Include runtime dependencies in the package; HTTP Functions do not auto-install `node_modules` for you.
13+
- For simple HTTP APIs, prefer the Node.js native `http` module so the function shape stays explicit and dependency-light. Only introduce Express, Koa, NestJS, or similar frameworks when the user explicitly asks for one or the service complexity justifies it.
1314

1415
## Minimal structure
1516

@@ -25,7 +26,7 @@ my-http-function/
2526

2627
```bash
2728
#!/bin/bash
28-
node index.js
29+
/var/lang/node18/bin/node index.js
2930
```
3031

3132
Requirements:
@@ -37,54 +38,148 @@ Requirements:
3738
## Minimal Node.js example
3839

3940
```javascript
40-
const express = require("express");
41-
const app = express();
41+
const http = require("http");
42+
const { URL } = require("url");
43+
44+
function sendJson(res, statusCode, data) {
45+
res.writeHead(statusCode, { "Content-Type": "application/json; charset=utf-8" });
46+
res.end(JSON.stringify(data));
47+
}
48+
49+
function readJsonBody(req) {
50+
return new Promise((resolve, reject) => {
51+
let raw = "";
52+
53+
req.on("data", (chunk) => {
54+
raw += chunk;
55+
});
56+
57+
req.on("end", () => {
58+
if (!raw) {
59+
resolve({});
60+
return;
61+
}
62+
63+
try {
64+
resolve(JSON.parse(raw));
65+
} catch (error) {
66+
reject(new Error("Invalid JSON body"));
67+
}
68+
});
69+
70+
req.on("error", reject);
71+
});
72+
}
73+
74+
const server = http.createServer(async (req, res) => {
75+
const url = new URL(req.url || "/", "http://127.0.0.1");
76+
77+
if (req.method === "GET" && url.pathname === "/health") {
78+
sendJson(res, 200, { ok: true });
79+
return;
80+
}
4281

43-
app.use(express.json());
82+
if (req.method === "POST" && url.pathname === "/echo") {
83+
try {
84+
const body = await readJsonBody(req);
85+
sendJson(res, 200, { received: body });
86+
} catch (error) {
87+
sendJson(res, 400, { error: error.message });
88+
}
89+
return;
90+
}
4491

45-
app.get("/health", (req, res) => {
46-
res.json({ ok: true });
92+
sendJson(res, 404, { error: "Not Found" });
4793
});
4894

49-
app.listen(9000);
95+
server.listen(9000);
5096
```
5197

98+
## Code-writing rules
99+
100+
- Do not write HTTP Functions as `exports.main = async (event, context) => {}`. That is the Event Function contract.
101+
- Start an HTTP server explicitly with `http.createServer(...)` or a framework app, and always bind to port `9000`.
102+
- Treat routing, method checks, and body parsing as part of the function code. With the native `http` module, parse `req.url` yourself and read the request body from the stream before calling `JSON.parse`.
103+
- Return JSON responses explicitly and set `Content-Type` yourself, for example `application/json; charset=utf-8`.
104+
- Keep unsupported routes and methods explicit. Return `404` for unknown paths, and return `405` when the path exists but the HTTP method is not allowed.
105+
- Keep `scf_bootstrap`, `index.js`, `package.json`, and any bundled dependencies in the function directory that will be uploaded.
106+
52107
## Request handling rules
53108

54-
- `req.query` -> query string values.
55-
- `req.body` -> parsed request body, but only after body-parsing middleware is configured.
109+
- With Node native `http`, use `new URL(req.url, "http://127.0.0.1")` and read `url.searchParams` for query values.
110+
- With Node native `http`, `req.body` does not exist. Read the body stream manually, then parse JSON yourself.
56111
- `req.headers` -> incoming HTTP headers.
57-
- `req.params` -> path parameters.
58-
- Always send a response with `res.json()`, `res.send()`, or `res.status(...).json()`.
112+
- Path parameters are framework-level conveniences. With the native `http` module, match `url.pathname` yourself.
113+
- Always send a response explicitly. With Node native `http`, use `res.writeHead(...)` and `res.end(...)`.
59114
- Return meaningful status codes such as `400`, `401`, `404`, `405`, `500`.
60115

61116
### Example with method checks
62117

63118
```javascript
64-
const express = require("express");
65-
const app = express();
66-
67-
app.use(express.json());
68-
69-
app.post("/users", (req, res) => {
70-
const { name, email } = req.body;
71-
72-
if (!name || !email) {
73-
return res.status(400).json({ error: "name and email are required" });
119+
const http = require("http");
120+
const { URL } = require("url");
121+
122+
function sendJson(res, statusCode, data) {
123+
res.writeHead(statusCode, { "Content-Type": "application/json; charset=utf-8" });
124+
res.end(JSON.stringify(data));
125+
}
126+
127+
function readJsonBody(req) {
128+
return new Promise((resolve, reject) => {
129+
let raw = "";
130+
131+
req.on("data", (chunk) => {
132+
raw += chunk;
133+
});
134+
135+
req.on("end", () => {
136+
if (!raw) {
137+
resolve({});
138+
return;
139+
}
140+
141+
try {
142+
resolve(JSON.parse(raw));
143+
} catch (error) {
144+
reject(new Error("Invalid JSON body"));
145+
}
146+
});
147+
148+
req.on("error", reject);
149+
});
150+
}
151+
152+
const server = http.createServer(async (req, res) => {
153+
const url = new URL(req.url || "/", "http://127.0.0.1");
154+
155+
if (url.pathname === "/users" && req.method === "POST") {
156+
try {
157+
const { name, email } = await readJsonBody(req);
158+
159+
if (!name || !email) {
160+
sendJson(res, 400, { error: "name and email are required" });
161+
return;
162+
}
163+
164+
sendJson(res, 201, { name, email });
165+
} catch (error) {
166+
sendJson(res, 400, { error: error.message });
167+
}
168+
169+
return;
74170
}
75171

76-
return res.status(201).json({ name, email });
77-
});
172+
if (url.pathname === "/users") {
173+
sendJson(res, 405, { error: "Method Not Allowed" });
174+
return;
175+
}
78176

79-
app.all("/{*splat}", (req, res) => {
80-
res.status(405).json({ error: "Method Not Allowed" });
177+
sendJson(res, 404, { error: "Not Found" });
81178
});
82179

83-
app.listen(9000);
180+
server.listen(9000);
84181
```
85182

86-
Express 5 note: do not use bare `*` or `/*` here. Express 5 uses `path-to-regexp` with named wildcards, so `app.all("/{*splat}", ...)` is the safe catch-all form when you also need to match the root path `/`.
87-
88183
## Deployment flow
89184

90185
Prefer `manageFunctions` over CLI in agent flows.

0 commit comments

Comments
 (0)