Skip to content

Node.js 云函数

云函数让您可以运行 JavaScript 后端代码,处理动态 API 请求、操作文件、调用外部 API 等。只需将文件命名为 .node.js 结尾(如 api.node.js),代码就会在服务器后端执行。

第一个云函数

在文件列表中创建一个以 .node.js 结尾的 JavaScript 文件,例如 hello.node.js。这个文件将包含如下云函数代码:

js
document.write("Hello, World!");

访问这个文件,您会看到「Hello, World!」。就这么简单!

由于代码在服务器上运行,当您通过浏览器开发者工具检查时,不会看到任何 JavaScript 代码,只会看到运行结果,因为代码是在服务器后端动态执行的。

获取请求信息

我们提供了全局的 req 对象,其风格受 Express.js 启发。您可以使用 req 对象访问请求参数。同时,我们实现了一些浏览器前端风格的接口,可以用和前端一样的方式获取信息,方便前端开发者快速上手。

访问查询参数

您可以通过 req.query 访问 URL 查询参数。例如,当网址带有 ?name=Alice 时,您可以这样获取 name 参数的值:

js
const name = req.query.name;
document.write(name); // 输出 "Alice"

您也可以通过 location.search 获取查询字符串:

js
document.write(location.search); // 输出 "?name=Alice"

访问 POST 参数

对于 POST 请求,您可以通过 req.body 访问请求体中的参数。例如,假设您发送了一个包含 message=Hello 的 POST 请求,您可以这样获取 message 参数的值:

js
const message = req.body.message;
document.write(message); // 输出 "Hello"

获取请求头

您可以通过 req.headers 访问请求头的键值对。例如,获取名为 Accept-Language 的请求头:

js
const acceptLanguage = req.headers["accept-language"];
document.write(acceptLanguage);

您可以通过 req.cookies 访问请求中的 Cookie。例如,获取名为 sessionId 的 Cookie:

js
const sessionId = req.cookies.sessionId;
document.write(sessionId);

获取用户代理

您可以从请求头中获取用户代理信息,了解访客使用的浏览器和操作系统。

js
const userAgent = req.headers["user-agent"];
document.write(userAgent);

您也可以通过 navigator.userAgent 获取用户代理信息:

js
document.write(navigator.userAgent);

获取来源网址

您可以通过 req.headers.refererdocument.referrer 获取请求的来源网址,即用户从哪个页面来到当前页面。

拼写差异

由于 HTTP 历史原因,req.headers 中的拼写是「referer」而不是「referrer」,但在 document 中是正确的拼写。

js
document.write(req.headers.referer);
document.write(document.referrer);

获取访客 IP 地址

您可以通过 req.ip 获取访客的 IP 地址:

js
const ip = req.ip;
document.write(ip);

获取当前网址

您可以通过 req.urllocation.href 获取当前请求的完整网址:

js
const url = req.url;
document.write(url);

获取请求方法

您可以通过 req.method 获取当前请求方法(如 GET、POST 等):

js
const method = req.method;
document.write(method); // 输出 "GET" 或 "POST"

响应请求

您可以使用全局的 res 对象来设置响应头和状态码,并发送响应内容。

输出内容

您可以使用这些函数输出内容:

  • console.log
  • document.write
  • res.write

这些函数的功能是相同的。它们都可以被多次调用,输出的内容会按调用顺序拼接在一起,作为响应体发送给客户端。如果您用过 PHP,这与使用 echo 输出内容类似。

js
res.write("Hello, ");
res.write("World");
res.write("!");

您会看到输出结果为 "Hello, World!"。

由于没有服务器控制台,console.log 的输出等同于 document.write,会直接输出到响应内容中。

输出内容并退出

如果您希望输出一次内容后立即退出程序,可以使用以下函数:

  • res.end
  • res.send

这两个函数的功能是相同的。如果您用过 PHP,这相当于 echo 后马上调用 exit

js
res.end("Goodbye, World!");
res.write("This will not be sent.");

您会看到输出结果只有 "Goodbye, World!",因为后续的代码不会被执行。

输出 JSON

如果您想输出 JSON 格式的数据,可以使用 res.json 函数。这个函数会自动将 JSON 转换为字符串,设置适当的响应头,发送给客户端,并退出程序。

js
const data = { message: "Hello, JSON!" };
res.json(data);

您会看到输出结果为 {"message": "Hello, JSON!"},其后续代码不会被执行。

设置响应状态码

默认情况下,状态码为 200(成功)。您可以使用 res.status 函数更改响应的 HTTP 状态码。例如,设置状态码为 404(未找到):

js
res.status(404);

您也可以通过直接更改 res.statusCode 的值来设置状态码:

js
res.statusCode = 404;

您可以在 MDNHTTP Cats 查看各个状态码的含义。

设置响应头

您可以使用 res.setHeaderres.set 函数设置响应头。例如,设置缓存时长为 1 小时:

js
res.setHeader("Cache-Control", "max-age=3600");

您可以使用 res.cookie 函数设置 Cookie。例如,设置一个名为 username 的 Cookie,值为 Alice,并设置过期时间为 7 天:

js
res.cookie("username", "Alice", { maxAge: 7 * 24 * 60 * 60 * 1000 });

重定向跳转

res.redirect 函数将当前请求重定向到另一个网址,并退出程序。

例如,将当前请求重定向到百度首页:

js
res.redirect("https://www.baidu.com/");

您也可以使用和前端一样的方式进行重定向,这和 res.redirect 行为一致:

js
location.href = "https://www.baidu.com/";

如果您想让浏览器和搜索引擎知道这是一个永久重定向,可以传入响应状态码 301:

js
res.redirect(301, "https://www.baidu.com/");

提前退出程序

如果您想在某些条件下提前终止程序执行,可以使用 process.exit() 函数,这会立即停止程序运行。

js
document.write("1");
process.exit();
document.write("2");

您会看到输出结果只有 "1",因为程序在执行到 process.exit() 时就停止了,后续代码不会被执行。

读写文件

您可以使用内置的 fs 模块读写同网站上的文件,用法与 Node.js 基本一致。我们的 fs 是一个全局对象,无需使用 importrequire 导入,直接使用即可。目前只支持非异步函数。

读取文件

您可以使用 fs.readFileSync 读取文件内容。例如,读取当前网站下的 data.txt 文件:

js
const content = fs.readFileSync("data.txt");
document.write(content);

如果文件不存在,会抛出错误。您可以使用 fs.existsSync 先判断文件是否存在:

js
if (fs.existsSync("data.txt")) {
	const content = fs.readFileSync("data.txt");
	document.write(content);
} else {
	document.write("文件不存在。");
}

如果您更熟悉前端的写法,您也可以使用 localStorage 来读写文件内容,效果与 fs 相同:

js
const content = localStorage.getItem("data.txt");
document.write(content);

请注意

如果您要读写的文件位于某个文件夹中,不管云函数文件在哪里,都需要使用完整的绝对路径。在热铁盒网页托管,/ 是文件名的一部分,因此不支持相对路径。假设您要读写的文件在 databases 文件夹中,那么您的代码应该是这样的:

js
const content = fs.readFileSync("databases/data.txt");
document.write(content);

读取 JSON 文件

您可以使用 fs.readFileSync 读取 JSON 文件内容,然后使用 JSON.parse 将其转换为 JS 对象。例如,读取当前网站下的 data.json 文件:

js
const content = fs.readFileSync("data.json");
const data = JSON.parse(content);

写入文件

您可以使用 fs.writeFileSynclocalStorage.setItem 写入文件内容。例如,向当前网站下的 data.txt 文件写入新内容覆盖原有内容:

js
fs.writeFileSync("data.txt", "Hello, File!");
localStorage.setItem("data.txt", "Hello, File!");

出于安全原因,不能写入 CSS、JavaScript、PHP 等类型的代码文件。

请注意

由于技术限制,目前只有当网站的文本文件总大小不超过 4 MB 时,才能读写文件和引入其他文件。您可以在写入前使用 os.diskFreeSpace() 检查剩余空间:

js
const freeSpace = os.diskFreeSpace();
document.write(`剩余空间:${freeSpace} 字节`);

如需存储用户数据,请使用数据库。数据库不限制总空间大小。

写入 JSON 文件

您可以使用 JSON.stringify 将 JS 对象转换为字符串,然后使用 fs.writeFileSync 写入 JSON 文件。例如,向当前网站下的 data.json 文件写入数据:

js
const data = { key: "value" };
fs.writeFileSync("data.json", JSON.stringify(data));

列出文件

您可以使用 fs.readdirSync 列出当前网站下的所有文件和文件夹。例如,列出当前网站下的所有文件:

js
const files = fs.readdirSync(".");
document.write(files);

引入其他文件

您可以使用 require() 函数引入同网站上的其他 Node.js 云函数,实现代码模块化。这与 Node.js 的 CommonJS 模块系统类似。

导出模块

在被引入的文件中,您可以使用 module.exports 导出函数、对象或变量。例如,创建一个 utils.node.js 文件:

js
function add(a, b) {
	return a + b;
}

function greet(name) {
	return `Hello, ${name}!`;
}

module.exports = { add, greet };

引入模块

在云函数文件中,使用 require() 引入其他文件。例如,在 api.node.js 中引入上面的 utils.node.js

js
const utils = require("utils.node.js");

const message = utils.greet("Alice");
document.write(message); // 输出 "Hello, Alice!"

const sum = utils.add(3, 5);
document.write(sum); // 输出 8

请注意

与读写文件类似,如果被引入的文件位于某个文件夹中,需要使用完整的路径。例如,如果 utils.node.jslib 文件夹中,应该这样引入:

js
const utils = require("lib/utils.node.js");

引入 JSON 文件

除了引入 JavaScript 模块,您也可以使用 require() 直接引入 JSON 文件。require() 会自动解析 JSON 文件并返回对应的对象,无需手动调用 JSON.parse()

例如,假设您有一个 config.json 文件:

json
{
	"appName": "我的应用",
	"version": "1.0.0"
}

您可以这样引入并使用:

js
const config = require("config.json");

document.write(config.appName); // 输出 "我的应用"
document.write(config.version); // 输出 "1.0.0"

fs.readFileSync 的区别是,使用 require() 引入 JSON 文件时,文件内容会被缓存,直到下次运行云函数时才会重新读取。fs.readFileSync 则每次都会读取最新的文件内容。

Node.js 内置模块

您可以引入 Node.js 内置模块来扩展云函数的功能。目前支持以下模块:

  • crypto:用于加密和解密数据。
  • fs:用于读写文件。
  • os:用于获取操作系统相关信息。
  • path:用于处理和转换文件路径。
  • process:用于控制当前 Node.js 进程。
  • querystring:用于解析和格式化 URL 查询字符串。

与标准的差异

云函数运行在热铁盒自研的 Serverless 环境中,和传统的 Node.js 运行环境有一些差异。目前暂不支持安装 npm 依赖。