Cloudflare Workers“单例”class
Cloudflare Workers “Singleton” class
我已经开始为我的网站使用工作人员。我网站上工作人员的目的:
主要是在 HTML 页面的不同位置注入一些代码(html/js/css)。
可以是一些配置数据,也可以是一些法律文本等
所以我现在要做的是在 KV 中为每个网站创建一个配置,并基于用户 country/language 在 html/js 之上注入等等
下面是一个 Store Class(单例模式),它保存了配置中的所有信息,但在 worker 中不起作用,by 不起作用 我的意思是,在第一次请求后,数据是持续存在,并在一段时间后更新:
例如第一个请求 URL:/about
在第二次请求 URL 时:/es/about/
通过输出 console.log(event.request)
将显示 /es/about
,但 Store.request
输出: /about/
任何解决此问题的方法,强制刷新数据,我想因为我不在构造函数中这样做,但通过调用自定义方法应该可以解决问题,但事实并非如此。?
下面是一些代码示例。
import { Store } from "@helpers/store";
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
});
//HTML Rewriter Class
class Head {
element(el) {
el.append(`
<script id="config">
var config = ${Store.export()};
</script>`, {
html: true
});
}
}
async function handleRequest(request) {
let store = await Store.make(request);
const response = await fetch(request);
let html = new HTMLRewriter();
html.on("head", new Head());
return html.transform(response);
}
//src/helpers/store.js
class Store {
constructor(){
this._request = null
this._config = {}
this._url = null
}
async make(request){
let config = {}
this._request = request;
const domain = this.url.hostname.replace(/www\./g, "");
const country = request.headers.get('cf-ipcountry')
const website = await WEBSITES.get(domain, "json"); //WEBSITES is KV namespace
const { license, lang } = website;
this._config = {
country,
domain,
license,
lang
};
return this;
}
export(){
return JSON.stringify(this._config)
}
get request(){
return this._request;
}
get url(){
if(!this._url){
this._url = new URL(this.request.url)
}
return this._url;
}
}
export default new Store()
您的 Worker 的单个实例可以处理多个请求,包括并发请求。在您的代码中,您正在使用 Store
的单例实例来存储有关当前请求的元数据。但是如果并发处理多个请求,那么在第一个请求完成之前,第二个请求将覆盖 Store
的内容。这可能会导致第一个请求使用第二个请求的元数据呈现其 HTML。
您在这里似乎不希望使用单例模式。根据代码,您似乎真的想为每个请求创建一个单独的 Store
实例。
想到了 2 个问题:
- 您正在为每次调用 worker 创建一个新的 HTMLRewriter。这将导致一些并发问题。重写器的实例化应该在 handleRequst 方法之外完成。例如在导入语句之后。
- 您正在导入 Store class 并且从不实例化它,而是像它们是静态的(它们不是)一样使用它的方法。这也会给您带来并发问题。
我已经开始为我的网站使用工作人员。我网站上工作人员的目的: 主要是在 HTML 页面的不同位置注入一些代码(html/js/css)。 可以是一些配置数据,也可以是一些法律文本等
所以我现在要做的是在 KV 中为每个网站创建一个配置,并基于用户 country/language 在 html/js 之上注入等等
下面是一个 Store Class(单例模式),它保存了配置中的所有信息,但在 worker 中不起作用,by 不起作用 我的意思是,在第一次请求后,数据是持续存在,并在一段时间后更新:
例如第一个请求 URL:/about
在第二次请求 URL 时:/es/about/
通过输出 console.log(event.request)
将显示 /es/about
,但 Store.request
输出: /about/
任何解决此问题的方法,强制刷新数据,我想因为我不在构造函数中这样做,但通过调用自定义方法应该可以解决问题,但事实并非如此。?
下面是一些代码示例。
import { Store } from "@helpers/store";
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
});
//HTML Rewriter Class
class Head {
element(el) {
el.append(`
<script id="config">
var config = ${Store.export()};
</script>`, {
html: true
});
}
}
async function handleRequest(request) {
let store = await Store.make(request);
const response = await fetch(request);
let html = new HTMLRewriter();
html.on("head", new Head());
return html.transform(response);
}
//src/helpers/store.js
class Store {
constructor(){
this._request = null
this._config = {}
this._url = null
}
async make(request){
let config = {}
this._request = request;
const domain = this.url.hostname.replace(/www\./g, "");
const country = request.headers.get('cf-ipcountry')
const website = await WEBSITES.get(domain, "json"); //WEBSITES is KV namespace
const { license, lang } = website;
this._config = {
country,
domain,
license,
lang
};
return this;
}
export(){
return JSON.stringify(this._config)
}
get request(){
return this._request;
}
get url(){
if(!this._url){
this._url = new URL(this.request.url)
}
return this._url;
}
}
export default new Store()
您的 Worker 的单个实例可以处理多个请求,包括并发请求。在您的代码中,您正在使用 Store
的单例实例来存储有关当前请求的元数据。但是如果并发处理多个请求,那么在第一个请求完成之前,第二个请求将覆盖 Store
的内容。这可能会导致第一个请求使用第二个请求的元数据呈现其 HTML。
您在这里似乎不希望使用单例模式。根据代码,您似乎真的想为每个请求创建一个单独的 Store
实例。
想到了 2 个问题:
- 您正在为每次调用 worker 创建一个新的 HTMLRewriter。这将导致一些并发问题。重写器的实例化应该在 handleRequst 方法之外完成。例如在导入语句之后。
- 您正在导入 Store class 并且从不实例化它,而是像它们是静态的(它们不是)一样使用它的方法。这也会给您带来并发问题。