使用 Deno 构建无服务器函数
为什么选择 Deno?
当你开始构建无服务器函数时,你可以立即使用 Deno 提高生产力
- 无需配置你的工具链、项目和 TypeScript,因为 Deno 自带现代开发工具链,并原生支持 TypeScript
- 使用你熟悉的 Web 平台 API,例如
fetch()
、压缩流、BroadcastChannel
、web workers、WebSocket
等 - 使用 Deno 的选择性加入权限系统来缓解供应链攻击
- 使用内置于运行时的 Deno KV,只需一行代码即可添加状态
无服务器函数
使用 Deno 构建无服务器函数就像创建一个接受请求并返回响应的 Web 服务器一样简单
Deno.serve((req) => new Response("Hello world"));
在我们的手册中了解更多关于 Deno.serve()
的信息。
这是一个更高级的无服务器函数示例,它可以根据一组查询字符串参数调整图像大小
import {
ImageMagick,
initializeImageMagick,
MagickGeometry,
} from "https://deno.land/x/[email protected]/mod.ts";
import { parseMediaType } from "https://deno.land/[email protected]/media_types/parse_media_type.ts";
await initializeImageMagick();
function parseParams(reqUrl: URL) {
const image = reqUrl.searchParams.get("image");
if (image == null) {
return "Missing 'image' query parameter.";
}
const height = Number(reqUrl.searchParams.get("height")) || 0;
const width = Number(reqUrl.searchParams.get("width")) || 0;
if (height === 0 && width === 0) {
return "Missing non-zero 'height' or 'width' query parameter.";
}
if (height < 0 || width < 0) {
return "Negative height or width is not supported.";
}
const maxDimension = 2048;
if (height > maxDimension || width > maxDimension) {
return `Width and height cannot exceed ${maxDimension}.`;
}
const mode = reqUrl.searchParams.get("mode") || "resize";
if (mode !== "resize" && mode !== "crop") {
return "Mode not accepted: please use 'resize' or 'crop'.";
}
return {
image,
height,
width,
mode,
};
}
async function getRemoteImage(image: string) {
const sourceRes = await fetch(image);
if (!sourceRes.ok) {
return "Error retrieving image from URL.";
}
const mediaType = parseMediaType(sourceRes.headers.get("Content-Type")!)[0];
if (mediaType.split("/")[0] !== "image") {
return "URL is not image type.";
}
return {
buffer: new Uint8Array(await sourceRes.arrayBuffer()),
mediaType,
};
}
function modifyImage(
imageBuffer: Uint8Array,
params: { width: number; height: number; mode: "resize" | "crop" },
) {
const sizingData = new MagickGeometry(
params.width,
params.height,
);
sizingData.ignoreAspectRatio = params.height > 0 && params.width > 0;
return new Promise<Uint8Array>((resolve) => {
ImageMagick.read(imageBuffer, (image) => {
if (params.mode === "resize") {
image.resize(sizingData);
} else {
image.crop(sizingData);
}
image.write((data) => resolve(data));
});
});
}
Deno.serve(
async (req: Request) => {
const reqURL = new URL(req.url);
const params = parseParams(reqURL);
if (typeof params === "string") {
return new Response(params, { status: 400 });
}
const remoteImage = await getRemoteImage(params.image);
if (remoteImage === "string") {
return new Response(remoteImage, { status: 400 });
}
const modifiedImage = await modifyImage(remoteImage.buffer, params);
return new Response(modifiedImage, {
headers: {
"Content-Type": remoteImage.mediaType,
},
});
},
);
更复杂的无服务器函数可以
- 访问浏览器 API,例如地理定位
- 通过覆盖 HTTP 内容来个性化用户体验
- 处理用户身份验证和会话请求
- 调整图像大小
- 动态生成 OG 和 meta 图像
- 处理 Discord 或 Slack 机器人的请求
以及更多。
使用 Deno KV 添加状态
Deno KV 是一个全局复制的数据库,是为你的服务器添加状态的最简单方法。 你无需复制或粘贴环境变量,也无需单独的步骤来配置数据库。 你只需要一行代码
const kv = await Deno.openKv();
你可以为你的无服务器函数添加状态,以便它们可以跨会话存储用户信息,从而解锁全新的用例和功能。
Node 呢?
在 Node.js 中,在为你的函数添加状态之前,你需要注册一个云数据库提供商,设置一个新的数据库,获取必要的 API 密钥和唯一地址,并将它们设置为环境变量。将你的无服务器函数部署到 Deno Deploy
Deno Deploy 是我们的无服务器边缘平台,允许你在靠近用户的边缘托管和运行你的函数。 你的无服务器函数将具有高可用性和最小的网络延迟。
通过连接 GitHub 帐户,在 Deno Deploy 上托管你的函数既简单又免费。
你还可以将你的 Deno 无服务器函数部署到 Cloudflare。
更多资源
这里有一些关于使用 Deno 构建无服务器函数的示例、博客文章和视频。