Worker threw exception / Body has already been used

Hello! I created this Worker to detect when a page on my website has the string data-error="404" in the body and set the appropriate HTTP response code. I also created a Worker Route for mysite.tld/* and this works perfectly for error pages that have the data-error string, but for "normal" pages the error "Error 1101 Worker threw exception" is generated. In the Worker's Quick Edit console I also see the error "Uncaught (in response) TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.", but I really couldn't wrap my head around resolving this. Any help?
export default {
async fetch(request) {
const response = await fetch(request)
const body = await response.text()
if (body.includes("html data-error=\"404\"")) {
return new Response(body, {
status: 404,
statusText: "Not Found",
headers: response.headers
})
} else {
return response
}
}
};
export default {
async fetch(request) {
const response = await fetch(request)
const body = await response.text()
if (body.includes("html data-error=\"404\"")) {
return new Response(body, {
status: 404,
statusText: "Not Found",
headers: response.headers
})
} else {
return response
}
}
};
5 Replies
Chaika
Chaika•5mo ago
fetch returns a response, the response has a .body in a ReadableStream/streamed back to you. .text() consumes the entire body and streams it into text. You can't then return the body, you already consumed it. You could clone it before using text, if you wanted that to work. This code is really inefficient though. Bodies could be large, and images/etc would also be looked through by this. You should check the response content type and only look at html responses at least
Francisco
Francisco•5mo ago
Is this better or worse than the original code (fortunately this modification solved the problem!)?
export default {
async fetch(request) {
const response = await fetch(request);
const contentType = response.headers.get("content-type");
if (contentType && contentType.includes("text/html")) {
const body = await response.text();
if (body.includes("html data-error=\"404\"")) {
return new Response(body, {
status: 404,
statusText: "Not Found",
headers: response.headers,
});
} else {
return new Response(body, response);
}
} else {
return response;
}
},
};
export default {
async fetch(request) {
const response = await fetch(request);
const contentType = response.headers.get("content-type");
if (contentType && contentType.includes("text/html")) {
const body = await response.text();
if (body.includes("html data-error=\"404\"")) {
return new Response(body, {
status: 404,
statusText: "Not Found",
headers: response.headers,
});
} else {
return new Response(body, response);
}
} else {
return response;
}
},
};
Disclaimer: yes this garbage was generated by ChatGPT, I'm still not that good with JavaScript
Chaika
Chaika•5mo ago
hmm... I think you'd just need
const body = await response.clone().text();
const body = await response.clone().text();
Francisco
Francisco•5mo ago
My code so bad I put Cloudflare down 😂 https://www.cloudflarestatus.com/
Cloudflare Status
Welcome to Cloudflare's home for real-time and historical data on system performance.
Francisco
Francisco•5mo ago
So I've reached the goal with this abomination of code, I have no idea how to improve it so I'll leave it at that - Luckily there are no errors on the console.
export default {
async fetch(request) {
let response = await fetch(request);
let contentType = response.headers.get("content-type");
if (contentType && contentType.includes("text/html")) {
let body = await response.text();
let dataErrorMatch = body.match(/html data-error="(\d+)"/);
if (dataErrorMatch && dataErrorMatch[1]) {
let httpStatusCode = parseInt(dataErrorMatch[1], 10);
if (!isNaN(httpStatusCode) && httpStatusCode >= 100 && httpStatusCode < 600) {
return new Response(body, {
status: httpStatusCode,
statusText: response.statusText,
headers: response.headers,
});
}
}
return new Response(body, response);
} else {
return response;
}
},
};
export default {
async fetch(request) {
let response = await fetch(request);
let contentType = response.headers.get("content-type");
if (contentType && contentType.includes("text/html")) {
let body = await response.text();
let dataErrorMatch = body.match(/html data-error="(\d+)"/);
if (dataErrorMatch && dataErrorMatch[1]) {
let httpStatusCode = parseInt(dataErrorMatch[1], 10);
if (!isNaN(httpStatusCode) && httpStatusCode >= 100 && httpStatusCode < 600) {
return new Response(body, {
status: httpStatusCode,
statusText: response.statusText,
headers: response.headers,
});
}
}
return new Response(body, response);
} else {
return response;
}
},
};
Thank you Chaika for the help MeowHeartCloudflare Marking the topic as Solved.