有的时候我们的需求,仅仅需要写一些很小的脚本,甚至不用考虑路由、第三方库。这种时候,Serverless函数就很符合我们的要求。甚至 Deno.land 和 CloudFlare Workers 还可以在线编写,一键部署,再合适不过了。
很多厂商提供Serverless函数供白嫖,如下表:
厂商 | 额度 |
---|---|
CloudFlare Workers | 10W请求/天 |
Vercel Edge Function | 50W请求/月 |
Deno Land | 100W请求/月 |
NodeJS/Deno 本地部署 | 无限制 |
然而,这些平台虽然有不少的相似之处,却也有一些差异,后续怎么集成到本地运行也存在问题。
但他们这些云函数都有一个共性,就是导出一个请求参数为Request返回值为Response的函数。
那我们只要用胶水语言做一些微小的操作,即可轻松让我们的代码同时兼容 Workers ,Deno,Vercel 和 NodeJS 。
下面的代码,只要在 handler 函数内实现你的逻辑,即可同时兼容 Workers
,Deno,Vercel 和 NodeJS
async function handler(request) {
return new Response("Hello World");
}
(async () => {
if (typeof Deno !== 'undefined') {
//For Deno
console.log(`Listening on http://localhost:${Deno.env.get("PORT") || 8000}`)
return Deno.serve({ port: Deno.env.get("PORT") || 8000 }, handler);
}
if (typeof EdgeRuntime !== 'undefined') {
//For vercel edge serverless
return
}
if (typeof addEventListener === "function") {
//For Cloudflare Workers
return
}
//For Nodejs
const { serve } = await eval("import('@hono/node-server')");
console.log(`Listening on http://localhost:${process.env.PORT || 8000}`)
serve({
fetch: handler,
port: process.env.PORT || 8000,
})
})()
//For vercel edge serverless - START
export const config = {
runtime: 'edge',
regions: ['hkg1'],
}
export const GET = handler
export const POST = handler
export const PUT = handler
export const PATCH = handler
export const DELETE = handler
export const HEAD = handler
export const OPTIONS = handler
//For vercel edge serverless - END
//For Cloudflare Pages Function - START
export function onRequest(context) {
return exports.fetch(context.request)
}
//For Cloudflare Pages Function - END
//For Cloudflare Workers Function - START
export default {
fetch(req, env, ctx) {
return handler(req);
}
}
//For Cloudflare Workers Function - END
为了使我们的代码尽可能地兼容不同的runtime,代码编写请遵守以下规范:
- 不使用第三方库,使用Fetch进行网络请求
- 不能使用Nodejs的流,可以使用const { readable, writable } = new TransformStream(); 操作流,使用 TextEncoder、TextDecoder解码流数据。
- Edge Runtime 这个链接的API支持可以作为参考。
这种Edge Serverless的开发,较Nodejs开发有一点限制。但是对于只需要实现简单功能的小工具来说,够用了。重要的是,可以很方便地在线编写,也可以使Serverless代码在几个云平台和本地之间直接迁移。
打个样,以下代码在 Workers ,Deno,Vercel 和 NodeJS 上可以无缝运行:
async function handler(request) {
if (request.method === "OPTIONS") {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
"Access-Control-Allow-Headers": '*'
}, status: 204
})
}
var msg = decodeURIComponent("%E5%95%8A%E5%95%8A%E5%95%8A%EF%BC%8C%E5%A5%BD%E7%97%9B%EF%BC%8C%E5%93%A5%E5%93%A5%E6%8F%92%E5%BE%97%E5%A4%AA%E6%B7%B1%E4%BA%86%EF%BC%81%EF%BC%81%EF%BC%81%EF%BC%81%EF%BC%81%EF%BC%81%EF%BC%81%EF%BC%81%EF%BC%81");
const { readable, writable } = new TransformStream();
const my_stream_writer = writable.getWriter();
var encoder = new TextEncoder();
; (async () => {
for (let i = 0; i < 10; i++) {
for (let j = 0; j < msg.length; j++) {
await sleep(20)
var txt = JSON.stringify({ "id": "chatcmpl-QXlha2FBbmROaXhpZUFyZUF3ZXNvbWUK", "object": "chat.completion.chunk", "created": null, "model": "gpt-3.5-turbo", "choices": [{ "index": 0, "delta": { "role": "assistant", "content": msg[j] }, "finish_reason": null }] })
await my_stream_writer.write(encoder.encode('data: ' + txt + '\n\n'));
}
}
await my_stream_writer.write(encoder.encode(`data: {"id":"chatcmpl-QXlha2FBbmROaXhpZUFyZUF3ZXNvbWUK","object":"chat.completion.chunk","created":null,"model":"gpt-3.5-turbo","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}\n\n`));
await my_stream_writer.close();
})()
return new Response(readable, {
headers: {
'Access-Control-Allow-Origin': '*',
"Access-Control-Allow-Headers": '*',
'Content-Type': 'text/event-stream; charset=UTF-8'
}, status: 200
})
}
function sleep(ms) {
return new Promise((r) => {
setTimeout(r, ms);
})
}
(async () => {
if (typeof Deno !== 'undefined') {
//For Deno
console.log(`Listening on http://localhost:${Deno.env.get("PORT") || 8000}`)
return Deno.serve({ port: Deno.env.get("PORT") || 8000 }, handler);
}
if (typeof EdgeRuntime !== 'undefined') {
//For vercel edge serverless
return
}
if (typeof addEventListener === "function") {
//For Cloudflare Workers
return
}
//For Nodejs
const { serve } = await eval("import('@hono/node-server')");
console.log(`Listening on http://localhost:${process.env.PORT || 8000}`)
serve({
fetch: handler,
port: process.env.PORT || 8000,
})
})()
//For vercel edge serverless - START
export const config = {
runtime: 'edge',
regions: ['hkg1'],
}
export const GET = handler
export const POST = handler
export const PUT = handler
export const PATCH = handler
export const DELETE = handler
export const HEAD = handler
export const OPTIONS = handler
//For vercel edge serverless - END
//For Cloudflare Pages Function - START
export function onRequest(context) {
return exports.fetch(context.request)
}
//For Cloudflare Pages Function - END
//For Cloudflare Workers Function - START
export default {
fetch(req, env, ctx) {
return handler(req);
}
}
//For Cloudflare Workers Function - END
mixed.zip (4.4 KB)
KV还没有封装,您可按照自己的使用习惯,自行实现。(CloudFlare Workers 、Deno 、和 Vercel 均支持 KV)