Skip to content

Commit 9af2940

Browse files
Add explicit UTF-8 charset to Cloudflare Worker JSON responses
Co-authored-by: richardthe3rd <573334+richardthe3rd@users.noreply.github.com>
1 parent e8816a3 commit 9af2940

1 file changed

Lines changed: 13 additions & 6 deletions

File tree

cloudflare-worker/worker.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export default {
4242
if (url.pathname === '/health') {
4343
return new Response(JSON.stringify({ status: 'ok' }), {
4444
headers: {
45-
'Content-Type': 'application/json',
45+
'Content-Type': 'application/json; charset=utf-8',
4646
...getCorsHeaders(request),
4747
},
4848
});
@@ -53,7 +53,7 @@ export default {
5353
return new Response(JSON.stringify(festivalsData), {
5454
status: 200,
5555
headers: {
56-
'Content-Type': 'application/json',
56+
'Content-Type': 'application/json; charset=utf-8',
5757
'Cache-Control': FESTIVALS_CACHE_CONTROL,
5858
...getCorsHeaders(request),
5959
},
@@ -81,6 +81,13 @@ export default {
8181
// Clone the response and add CORS headers
8282
const newHeaders = new Headers(response.headers);
8383
setCorsHeaders(newHeaders, request);
84+
85+
// Ensure JSON responses explicitly declare UTF-8 encoding
86+
// This prevents mojibake when non-ASCII characters (é, ö, ä, ñ) are present
87+
const contentType = newHeaders.get('Content-Type');
88+
if (contentType && contentType.includes('application/json') && !contentType.includes('charset')) {
89+
newHeaders.set('Content-Type', 'application/json; charset=utf-8');
90+
}
8491

8592
return new Response(response.body, {
8693
status: response.status,
@@ -91,7 +98,7 @@ export default {
9198
return new Response(JSON.stringify({ error: 'Proxy error', message: error.message }), {
9299
status: 502,
93100
headers: {
94-
'Content-Type': 'application/json',
101+
'Content-Type': 'application/json; charset=utf-8',
95102
...getCorsHeaders(request),
96103
},
97104
});
@@ -124,7 +131,7 @@ async function handleAvailableBeverageTypes(festivalId, request) {
124131
}), {
125132
status: 404,
126133
headers: {
127-
'Content-Type': 'application/json',
134+
'Content-Type': 'application/json; charset=utf-8',
128135
...getCorsHeaders(request),
129136
},
130137
});
@@ -142,7 +149,7 @@ async function handleAvailableBeverageTypes(festivalId, request) {
142149
}), {
143150
status: 200,
144151
headers: {
145-
'Content-Type': 'application/json',
152+
'Content-Type': 'application/json; charset=utf-8',
146153
'Cache-Control': 'public, max-age=3600', // Cache for 1 hour
147154
...getCorsHeaders(request),
148155
},
@@ -154,7 +161,7 @@ async function handleAvailableBeverageTypes(festivalId, request) {
154161
}), {
155162
status: 500,
156163
headers: {
157-
'Content-Type': 'application/json',
164+
'Content-Type': 'application/json; charset=utf-8',
158165
...getCorsHeaders(request),
159166
},
160167
});

0 commit comments

Comments
 (0)