跳转到内容
搜索文档

错误和异常

最后更新 查看 MarkdownAgent 设置

查看 Workers 错误和异常。

Worker 生成的错误页面

当生产环境中运行的 Worker 发生错误且无法返回响应时,客户端将收到带有错误代码的错误页面,定义如下:

错误代码 含义
1101 Worker 抛出了 JavaScript 异常。
1102 Worker 超出 CPU 时间限制
1103 此 Worker 的所有者需要联系 Cloudflare 支持
1019 Worker 达到循环限制
1021 Worker 请求了无法访问的主机。
1022 Cloudflare 未能将请求路由到 Worker。
1024 Worker 无法向 Cloudflare 拥有的 IP 地址发出子请求。
1027 Worker 超出免费套餐每日请求限制
1042 Worker 尝试从同一 zone 上的另一个 Worker 进行 fetch,仅在使用 global_fetch_strictly_public 兼容性标志受支持
10162 模块具有不支持的 Content-Type。

其他 11xx 错误通常表示 Workers 运行时本身存在问题。如果遇到错误,请参阅状态页面

循环限制

Worker 不能调用自身或其他 Worker 超过 16 次。为防止 Worker 之间的无限循环,CF-EW-Via 标头的值是一个整数,表示剩余调用次数。每次 Worker 被调用时,该整数减 1。如果计数达到零,将返回 1019 错误。

"The script will never generate a response" 错误

某些请求可能返回 1101 错误,错误消息中包含 The script will never generate a response。当 Workers 运行时检测到与请求关联的所有代码已执行完毕且事件循环中没有剩余事件,但尚未返回 Response 时,会发生此情况。

原因 1:未解决的 Promise

这通常是因为依赖了一个从未 resolve 或 reject 的 Promise,而返回 Response 需要 Promise 完成。调试时,请在代码或依赖项代码中查找阻塞 Response 的 Promise,并确保它们被 resolve 或 reject。

在浏览器和其他 JavaScript 运行时中,等效代码会无限挂起,导致 bug 和内存泄漏。Workers 运行时会抛出明确的错误以帮助您调试。

在下面的示例中,Response 依赖于一个永远不会完成的 Promise 解析。取消注释 resolve 回调即可解决问题。

export default {
	fetch(req) {
		let response = new Response("Example response");
		let { promise, resolve } = Promise.withResolvers();

		// If the promise is not resolved, the Workers runtime will
		// recognize this and throw an error.

		// setTimeout(resolve, 0)

		return promise.then(() => response);
	},
};

您可以通过强制执行 no-floating-promises eslint 规则 来防止此问题,该规则会在创建 Promise 但未正确处理时报告。

原因 2:从未关闭的 WebSocket 连接

如果 WebSocket 缺少关闭服务端连接的正确代码,Workers 运行时将抛出 script will never generate a response 错误。在下面的示例中,来自客户端的 'close' 事件未通过调用 server.close() 正确处理,因此抛出错误。为避免此问题,请确保通过事件监听器或其他服务端逻辑正确关闭 WebSocket 的服务端连接。

async function handleRequest(request) {
	let webSocketPair = new WebSocketPair();
	let [client, server] = Object.values(webSocketPair);
	server.accept();

	server.addEventListener("close", () => {
		// This missing line would keep a WebSocket connection open indefinitely
		// and results in "The script will never generate a response" errors
		// server.close();
	});

	return new Response(null, {
		status: 101,
		webSocket: client,
	});
}

"Illegal invocation" 错误

错误消息 TypeError: Illegal invocation: function called with incorrect this reference 可能令人困惑。

这通常是因为调用了依赖 this 的函数,但 this 的值已丢失。

例如,给定一个 obj 对象,其 obj.foo() 方法的逻辑依赖 this,通过 obj.foo(); 执行方法可确保 this 正确引用 obj 对象。然而,将方法赋值给变量,例如 const func = obj.foo;,然后调用该变量,例如 func();,会导致 thisundefined。这是因为方法作为独立函数调用时 this 会丢失。这是 JavaScript 的标准行为。

实践中,这常见于解构运行时提供的、其函数依赖 this 存在的 JavaScript 对象,例如 ctx

以下代码会出错:

export default {
	async fetch(request, env, ctx) {
		// destructuring ctx makes waitUntil lose its 'this' reference
		const { waitUntil } = ctx;
		// waitUntil errors, as it has no 'this'
		waitUntil(somePromise);

		return fetch(request);
	},
};

避免解构,或将函数重新绑定到原始上下文以避免错误。

以下代码可以正常运行:

export default {
	async fetch(request, env, ctx) {
		// directly calling the method on ctx avoids the error
		ctx.waitUntil(somePromise);

		// alternatively re-binding to ctx via apply, call, or bind avoids the error
		const { waitUntil } = ctx;
		waitUntil.apply(ctx, [somePromise]);
		waitUntil.call(ctx, somePromise);
		const reboundWaitUntil = waitUntil.bind(ctx);
		reboundWaitUntil(somePromise);

		return fetch(request);
	},
};

无法代表不同请求执行 I/O

Uncaught (in promise) Error: Cannot perform I/O on behalf of a different request. I/O objects (such as streams, request/response bodies, and others) created in the context of one request handler cannot be accessed from a different request's handler.

当您尝试在不同调用的上下文中共享由 Worker 某次调用创建的输入/输出(I/O)对象(如 stream、request 或 response)时,会发生此错误。

在 Cloudflare Workers 中,每次调用独立处理,拥有各自的执行上下文。此设计通过隔离请求来确保最佳性能和安全性。当您尝试在不同调用之间共享 I/O 对象时,会破坏这种隔离。由于这些对象与创建它们的特定请求绑定,从另一请求的处理程序访问它们是不允许的,并会导致此错误。

此错误最常见的原因是在全局作用域中缓存 I/O 对象(如 Request),然后在后续请求中访问它。例如,如果您创建 Worker 并在本地开发中运行以下代码,并快速连续向 Worker 发送两个请求,可以复现此错误:

let cachedResponse = null;

export default {
	async fetch(request, env, ctx) {
		if (cachedResponse) {
			return cachedResponse;
		}
		cachedResponse = new Response("Hello, world!");
		await new Promise((resolve) => setTimeout(resolve, 5000)); // Sleep for 5s to demonstrate this particular error case
		return cachedResponse;
	},
};

您可以通过在全局作用域中仅存储数据而非 I/O 对象本身来修复此问题:

let cachedData = null;

export default {
	async fetch(request, env, ctx) {
		if (cachedData) {
			return new Response(cachedData);
		}
		const response = new Response("Hello, world!");
		cachedData = await response.text();
		return new Response(cachedData, response);
	},
};

如果需要在请求之间共享状态,请考虑使用 Durable Objects。如果需要在请求之间缓存数据,请考虑使用 Workers KV

Worker 上传时的错误

这些错误在 Worker 上传或修改时发生。

错误代码 含义
10006 无法解析 Worker 代码。
10007 未找到 Worker 或 workers.dev 子域
10015 账户无权使用 Workers。
10016 Worker 名称无效。
10021 验证错误。详情请参阅验证错误
10026 无法解析请求体。
10027 上传的 Worker 超出 Worker 大小限制
10035 同时多次尝试修改资源
10037 账户超出允许的 Worker 数量
10052 上传的绑定(binding) 没有名称。
10054 环境变量或 secret 超出大小限制
10055 环境变量或 secret 数量超出每个 Worker 的限制
10056 未找到绑定(binding)
10068 上传的 Worker 没有注册的事件处理程序
10069 上传的 Worker 包含 Workers 运行时不支持的事件处理程序

验证错误 (10021)

10021 错误代码包括尝试部署 Worker 时发生的所有错误,此时 Cloudflare 尝试加载并运行顶层作用域(Worker 处理程序 被调用之前发生的一切)。例如,如果您尝试部署包含无效 JavaScript(会抛出 SyntaxError)的损坏 Worker——Cloudflare 将不会部署您的 Worker。

具体错误情况包括但不限于:

脚本启动超出 CPU 时间限制

这意味着您在 Worker 顶层作用域中执行的工作占用了超过 启动时间限制(1 秒) 的 CPU 时间。

脚本启动超出内存限制

这意味着您在 Worker 顶层作用域中执行的工作分配了超过 内存限制(128 MB) 的内存。

运行时错误

运行时错误发生在运行时内部,不会抛出错误页面,对最终用户不可见。用户通过日志检测运行时错误。

错误消息 含义
Network connection lost 连接失败。捕获 fetch 或绑定调用并重试。
Memory limit
would be exceeded
before EOF
尝试读取会使您超出内存限制 的 stream 或 buffer。
daemonDown 调用 Worker 时出现临时问题。

识别错误:Workers Metrics

要查看应用程序是否出现停机或返回错误:

  1. 在 Cloudflare 仪表板中,前往 Workers & Pages 页面。

    Go to Workers & Pages ↗
  2. Overview(概览) 中,选择 Worker 并查看其指标。

Worker 错误

Errors by invocation status(按调用状态划分的错误) 图表显示按以下类别细分的错误数量:

错误 含义
Uncaught Exception Worker 代码在执行期间抛出了 JavaScript 异常。
Exceeded CPU Time Limits Worker 超出 CPU 时间限制或其他资源约束。
Exceeded Memory Worker 在执行期间超出内存限制。
Internal Workers 运行时发生内部错误。

Client disconnected by type(按类型划分的客户端断开) 图表显示按以下类别细分的客户端断开连接错误数量:

客户端断开连接 含义
Response Stream Disconnected 连接在 Worker 请求流程的延迟代理阶段终止。常见于 WebSockets 等长连接。
Cancelled 客户端在 Worker 完成响应之前断开连接。

使用 Workers Logs 调试异常

Workers Logs 是调试 Workers 的强大工具。它显示 Worker 生成的所有历史日志,包括执行期间发生的任何未捕获异常。

要在 Workers Logs 中查找所有错误,可以使用以下筛选器:$metadata.error EXISTS。这将显示所有关联错误的日志。您还可以按 $workers.outcome 筛选以查找导致错误的请求。例如,可以按 $workers.outcome = "exception" 筛选以查找所有导致未捕获异常的请求。

所有可能的 outcome 值可在 Workers Trace Event 参考中找到。

使用 Wrangler 调试异常

要通过 wrangler 调试 Worker,使用 wrangler tail 检查并修复异常。

异常会显示在 wrangler tail 返回的 JSON 的 exceptions 字段下。识别导致错误的异常后,重新部署修复后的代码,并继续 tail 日志以确认问题已修复。

设置第三方日志服务

Worker 可以向公共 Internet 上的任何 HTTP 服务发出 HTTP 请求。您可以使用 Sentry 等服务,通过向服务发出 HTTP 请求来报告错误,从而从 Worker 收集错误日志。有关应发出何种请求的详情,请参阅服务的 API 文档。

使用外部日志策略时,请记住,浮动 promise(既未 await、未 return,也未传递给 ctx.waitUntil() 的 promise)可能在 Worker 调用完成时被取消。Worker 调用在向客户端流式传输响应体期间尚未完成。要在响应完成后运行日志记录,请将请求 promise 传递给 ctx.waitUntil()。例如:

export default {
	async fetch(request, env, ctx) {
		function postLog(data) {
			return fetch("https://log-service.example.com/", {
				method: "POST",
				body: data,
			});
		}

		// Without ctx.waitUntil(), the `postLog` function may or may not complete.
		ctx.waitUntil(postLog(stack));
		return fetch(request);
	},
};
addEventListener("fetch", (event) => {
	event.respondWith(handleEvent(event));
});

async function handleEvent(event) {
	// ...

	// Without event.waitUntil(), the `postLog` function may or may not complete.
	event.waitUntil(postLog(stack));
	return fetch(event.request);
}

function postLog(data) {
	return fetch("https://log-service.example.com/", {
		method: "POST",
		body: data,
	});
}

收集并持久化 Wasm core dumps

配置 Wasm Coredump Service,从 Rust Workers 应用程序收集 coredump,并将其持久化到日志、Sentry 或 R2,以便使用 wasmgdb 进行分析。阅读博客文章了解更多详情。

出错时回源

通过使用 passThroughOnException(),Workers 应用程序可以在 Worker 执行期间抛出异常时将请求转发到源站。这允许您使用 Workers 添加日志记录、跟踪或其他功能,而不会降低应用程序的功能。

ctx.passThroughOnException() 转发 Worker 代码中未处理异常的请求,而非源站 fetch() 的错误。向源站代理请求时,将 fetch(request) 包装在 try...catch 中,失败时返回 5xx 响应。如果源站 fetch() 在消耗请求体后抛出,passThroughOnException() 无法重放请求体。

export default {
	async fetch(request, env, ctx) {
		ctx.passThroughOnException();
		// an error here will return the origin response, as if the Worker wasn't present
		return fetch(request);
	},
};
addEventListener("fetch", (event) => {
	event.passThroughOnException();
	event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
	// An error here will return the origin response, as if the Worker wasn't present.
	// ...
	return fetch(request);
}

相关资源

这篇文档对您有帮助吗?