Skip to content

Commit f757fa3

Browse files
committed
feat: 實作ImageResponse也要控制http status code
1 parent fabe03d commit f757fa3

3 files changed

Lines changed: 35 additions & 32 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Demo <https://echo.yuaner.tw/assets/text/dict/textpar.html?ref=tablericons&utm_s
3232

3333
## 預覽
3434
![echo_preview_png](https://echo.yuaner.tw/?echo_png=1)
35+
![echo_403_preview_png](https://echo.yuaner.tw/?echo_code=403&echo_png=1)
3536

3637
PS. 本預覽圖因為有進Github CDN快取,所以在本頁面上看到的資訊很可能是Github CDN環境的狀況。請以實際用 `<原網址>/?echo_png=1` 直連取得到的為主。
3738

‎src/core.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ export default {
299299
},
300300
http: {
301301
method : finalMethod,
302+
status : responseStatus,
302303
baseUrl : `${url.protocol}//${url.host}`,
303304
originalUrl : url.pathname + url.search,
304305
protocol : url.protocol.replace(":", ""),

‎src/og.js‎

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const iconCache = new Map();
99
// Optimized helper to create React-element-like objects
1010
const h = (type, props, ...children) => {
1111
const style = props.style || {};
12-
12+
1313
// Satori rule: elements with > 1 children should have explicit display
1414
// We default everything to flex since that's what Satori expects
1515
// Flattening and filtering is expensive, we do it minimally
@@ -32,14 +32,14 @@ const h = (type, props, ...children) => {
3232
function icon(name) {
3333
const svg = tabler_icons_html[name];
3434
if (!svg) return null;
35-
35+
3636
if (!iconCache.has(name)) {
37-
const b64 = typeof btoa === 'function'
38-
? btoa(svg)
37+
const b64 = typeof btoa === 'function'
38+
? btoa(svg)
3939
: Buffer.from(svg).toString('base64');
4040
iconCache.set(name, b64);
4141
}
42-
42+
4343
return h('img', {
4444
src: `data:image/svg+xml;base64,${iconCache.get(name)}`,
4545
width: 24,
@@ -55,15 +55,15 @@ function objectToListElements(obj, limit = 20) {
5555
const hasMore = entries.length > limit;
5656

5757
const list = displayEntries.map(([k, v]) => {
58-
return h('div', {
59-
style: {
60-
display: 'flex',
61-
flexDirection: 'row',
62-
fontSize: baseFontSize - 2,
63-
marginBottom: 2,
58+
return h('div', {
59+
style: {
60+
display: 'flex',
61+
flexDirection: 'row',
62+
fontSize: baseFontSize - 2,
63+
marginBottom: 2,
6464
width: '100%',
6565
overflow: 'hidden'
66-
}
66+
}
6767
},
6868
h('span', { style: { fontWeight: 'bold', marginRight: 5, color: '#666', flexShrink: 0 } }, `${k}:`),
6969
h('span', { style: { wordBreak: 'break-all', color: '#333', flex: 1, height: 26, overflow: 'hidden' } }, String(v))
@@ -77,17 +77,17 @@ function objectToListElements(obj, limit = 20) {
7777
}
7878

7979
function hostCard(hostData) {
80-
return h('div', {
81-
style: {
82-
display: 'flex',
83-
flexDirection: 'column',
84-
border: '1px solid #ddd',
85-
padding: 20,
80+
return h('div', {
81+
style: {
82+
display: 'flex',
83+
flexDirection: 'column',
84+
border: '1px solid #ddd',
85+
padding: 20,
8686
backgroundColor: 'white',
8787
flex: 1,
8888
width: '100%',
8989
overflow: 'hidden'
90-
}
90+
}
9191
},
9292
h('h2', { style: { display: 'flex', alignItems: 'center', fontSize: baseFontSize, margin: '0 0 10px 0' } },
9393
icon('cloud_network'),
@@ -166,9 +166,9 @@ function endpointBar(responseBody) {
166166
export function generateOgImage(responseBody) {
167167
const method = responseBody.http.method;
168168
const bodyRaw = responseBody.request.bodyRaw;
169-
169+
170170
const showBody = !((method === 'GET' || method === 'HEAD') && (!bodyRaw || bodyRaw.trim() === ''));
171-
171+
172172
// Performance optimization: Manual 2-column layout instead of flexWrap
173173
const headerElements = objectToListElements(responseBody.request.headers, 24);
174174
const mid = Math.ceil(headerElements.length / 2);
@@ -191,36 +191,36 @@ export function generateOgImage(responseBody) {
191191

192192
h('div', { style: { display: 'flex', width: '100%', flex: 1, gap: 20 } },
193193
// Left Column (Request info)
194-
h('div', {
195-
style: {
196-
display: 'flex',
197-
flexDirection: 'column',
194+
h('div', {
195+
style: {
196+
display: 'flex',
197+
flexDirection: 'column',
198198
flex: 2,
199199
border: '1px solid #ddd',
200200
padding: 15,
201201
backgroundColor: 'white',
202202
overflow: 'hidden'
203-
}
203+
}
204204
},
205205
// Post Body block (if exists)
206206
showBody ? h('div', { style: { display: 'flex', flexDirection: 'column', marginBottom: 15 } },
207207
h('div', { style: { display: 'flex', alignItems: 'center', marginBottom: 5 } },
208208
icon('file'),
209209
h('span', { style: { fontSize: baseFontSize, fontWeight: 'bold' } }, 'Post Body')
210210
),
211-
h('div', {
212-
style: {
211+
h('div', {
212+
style: {
213213
display: 'flex',
214-
backgroundColor: '#f8f9fa',
215-
padding: 10,
214+
backgroundColor: '#f8f9fa',
215+
padding: 10,
216216
fontFamily: 'monospace',
217217
fontSize: baseFontSize - 4,
218218
maxHeight: 120,
219219
overflow: 'hidden',
220220
wordBreak: 'break-all',
221221
color: '#444',
222222
border: '1px solid #eee'
223-
}
223+
}
224224
}, (bodyRaw || '').substring(0, 300) + (bodyRaw && bodyRaw.length > 300 ? '...' : ''))
225225
) : null,
226226

@@ -236,7 +236,7 @@ export function generateOgImage(responseBody) {
236236
h('div', { style: { display: 'flex', flexDirection: 'column', flex: 1 } }, ...rightHeaders)
237237
)
238238
),
239-
239+
240240
// Right Column (Host info)
241241
h('div', { style: { display: 'flex', flexDirection: 'column', flex: 1} },
242242
hostCard(responseBody.host)
@@ -247,5 +247,6 @@ export function generateOgImage(responseBody) {
247247
return new ImageResponse(element, {
248248
width: 1200,
249249
height: 630,
250+
status: responseBody.http.status || 200,
250251
});
251252
}

0 commit comments

Comments
 (0)