fix(openflare): improve SWOfflineDomains validation and snapshot diff logic

This commit is contained in:
ryan
2026-08-08 20:52:07 +08:00
parent 6882481a56
commit 9797fcdb2f
8 changed files with 42 additions and 6 deletions
+5
View File
@@ -26,6 +26,11 @@ sidebar: false
- 支持 Service Worker 离线兜底:为启用 HTTPS 的网站下发 Service Worker 并缓存离线联系页,域名无法访问时浏览器展示联系站长页面,减少用户流失。可指定生效域名范围(仅对选中的 HTTPS 域名生效),配置位于「响应页面」-「联系页」,可在版本发布中批量生效。
### 修复
- 修复 `SWOfflineDomains` 校验与版本比对逻辑:校验器严格拒绝 JSON `null` 输入,配置版本 Diff 比对改用 JSON 序列化避免 `strings.Join` 逗号分隔符歧义。
- 修复 HTML 编辑器预览标题:`HtmlEditorWorkspace` 支持传入 `previewTitle`,离线联系页预览使用「离线联系页实时预览」。
### 改进
- 响应页面统一:将源站错误页与 Service Worker 离线兜底联系页整合至统一的「响应页面」(`/responses`)标签页中,移除原 `/error-pages` 独立路由。
@@ -194,6 +194,7 @@ export function ContactPageTab({
preview={(html) => html}
footerHint={null}
showPreviewLink={false}
previewTitle='离线联系页实时预览'
/>
</CardContent>
</Card>
@@ -42,9 +42,7 @@ export function ErrorPageTab({
optionMap: Record<string, string>;
}) {
const queryClient = useQueryClient();
const [fields, setFields] = useState<ErrorPageFields>(
defaultErrorPageFields,
);
const [fields, setFields] = useState<ErrorPageFields>(defaultErrorPageFields);
const [tagError, setTagError] = useState<string | null>(null);
useEffect(() => {
@@ -21,6 +21,7 @@ type HtmlEditorWorkspaceProps = {
preview?: (html: string) => string;
footerHint?: React.ReactNode;
showPreviewLink?: boolean;
previewTitle?: string;
};
/**
@@ -38,6 +39,7 @@ export function HtmlEditorWorkspace({
</>
),
showPreviewLink = true,
previewTitle = '源站错误页实时预览',
}: HtmlEditorWorkspaceProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [editorWidthPercent, setEditorWidthPercent] = useState(48);
@@ -145,7 +147,7 @@ export function HtmlEditorWorkspace({
</div>
<div className='flex-1 min-h-0 overflow-hidden bg-background'>
<iframe
title='源站错误页实时预览'
title={previewTitle}
sandbox=''
srcDoc={previewSrcDoc}
className='h-full w-full border-0 bg-background'
@@ -540,7 +540,7 @@ func diffOpenRestyOptionDetails(left openRestyConfigSnapshot, right openRestyCon
appendIfChanged("OriginErrorPageGetOnly", fmt.Sprintf("%t", left.OriginErrorPageGetOnly), fmt.Sprintf("%t", right.OriginErrorPageGetOnly))
appendIfChanged("SWOfflineEnabled", fmt.Sprintf("%t", left.SWOfflineEnabled), fmt.Sprintf("%t", right.SWOfflineEnabled))
appendIfChanged("SWOfflineHTML", left.SWOfflineHTML, right.SWOfflineHTML)
appendIfChanged("SWOfflineDomains", strings.Join(left.SWOfflineDomains, ","), strings.Join(right.SWOfflineDomains, ","))
appendIfChanged("SWOfflineDomains", encodeSWOfflineDomains(left.SWOfflineDomains), encodeSWOfflineDomains(right.SWOfflineDomains))
return changes
}
@@ -555,6 +555,17 @@ func encodeOriginErrorPageStatusCodes(tags []string) string {
return string(payload)
}
func encodeSWOfflineDomains(domains []string) string {
if len(domains) == 0 {
return ""
}
payload, err := json.Marshal(domains)
if err != nil {
return strings.Join(domains, ",")
}
return string(payload)
}
func extractOptionDiffKeys(details []ConfigOptionDiffItem) []string {
keys := make([]string, 0, len(details))
for _, item := range details {
@@ -101,3 +101,21 @@ func TestDiffOpenRestyOptionDetailsOriginErrorPage(t *testing.T) {
assert.Equal(t, "", keys["OriginErrorPageHTML"].PreviousValue)
assert.Equal(t, "<p>x</p>", keys["OriginErrorPageHTML"].CurrentValue)
}
func TestDiffOpenRestyOptionDetailsSWOfflineDomains(t *testing.T) {
t.Parallel()
left := openRestyConfigSnapshot{
SWOfflineDomains: []string{"a.com,b.com"},
}
right := openRestyConfigSnapshot{
SWOfflineDomains: []string{"a.com", "b.com"},
}
details := diffOpenRestyOptionDetails(left, right)
keys := make(map[string]ConfigOptionDiffItem, len(details))
for _, item := range details {
keys[item.Key] = item
}
assert.Equal(t, `["a.com,b.com"]`, keys["SWOfflineDomains"].PreviousValue)
assert.Equal(t, `["a.com","b.com"]`, keys["SWOfflineDomains"].CurrentValue)
}
@@ -260,7 +260,7 @@ func validateSWOfflineHTML(key, value string) error {
func validateSWOfflineDomains(key, value string) error {
var domains []string
if err := json.Unmarshal([]byte(value), &domains); err != nil {
if err := json.Unmarshal([]byte(value), &domains); err != nil || domains == nil {
return fmt.Errorf("%s 必须为 JSON 字符串数组", key)
}
if len(domains) > maxSWOfflineDomains {
@@ -106,6 +106,7 @@ func TestValidateSWOfflineDomains(t *testing.T) {
{"single", `["example.com"]`, true},
{"multiple", `["example.com","api.example.com"]`, true},
{"invalid json", `not-json`, false},
{"null", "null", false},
{"empty element", `[""]`, false},
{"duplicate", `["example.com","example.com"]`, false},
{"whitespace dedup", `[" Example.com ","example.com"]`, false},