From 8d1bf6a451227fe1fc9e25490216ca4c335f9d8c Mon Sep 17 00:00:00 2001 From: ccbikai Date: Wed, 25 Dec 2024 12:15:00 +0800 Subject: [PATCH] feat: improve case-sensitive slug handling Refactors URL slug case sensitivity implementation: - Moves case conversion to creation time instead of lookup - Updates middleware to handle case sensitivity more efficiently - Adds configuration docs for case sensitivity and list query limits - Simplifies nanoid implementation to always use lowercase This change improves performance and consistency in URL handling while maintaining backwards compatibility with existing links. --- docs/configuration.md | 8 ++++++++ docs/faqs.md | 4 ++++ schemas/link.ts | 7 +------ server/api/link/create.post.ts | 6 ++++++ server/middleware/1.redirect.ts | 10 +++++----- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index a6be688..1f3a891 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -43,3 +43,11 @@ Default prompt: ```txt You are a URL shortening assistant, please shorten the URL provided by the user into a SLUG. The SLUG information must come from the URL itself, do not make any assumptions. A SLUG is human-readable and should not exceed three words and can be validated using regular expressions {slugRegex} . Only the best one is returned, the format must be JSON reference {"slug": "example-slug"} ``` + +## `NUXT_CASE_SENSITIVE` + +Set URL case sensitivity. + +## `NUXT_LIST_QUERY_LIMIT` + +Set the maximum query data volume for the Metric list. diff --git a/docs/faqs.md b/docs/faqs.md index 159536b..1b99866 100644 --- a/docs/faqs.md +++ b/docs/faqs.md @@ -42,3 +42,7 @@ However, you can disable this feature by setting the `NUXT_CASE_SENSITIVE` envir ### What happens when `NUXT_CASE_SENSITIVE` is `true`? Newly generated links will be case-sensitive, treating `MyLink` and `mylink` as distinct. Randomly generated slugs will include both uppercase and lowercase characters, offering a larger pool of unique combinations (but not user-friendly that why we default to non-case-sensitive). + +## 7. Why does the Metric list only show the top 500 data entries? + +To improve query performance, we have limited the amount of data. If you need to query more data, you can adjust it through `NUXT_LIST_QUERY_LIMIT`. diff --git a/schemas/link.ts b/schemas/link.ts index bae2041..c27397e 100644 --- a/schemas/link.ts +++ b/schemas/link.ts @@ -2,15 +2,10 @@ import { customAlphabet } from 'nanoid' import { z } from 'zod' const { slugRegex } = useAppConfig() -const { caseSensitive } = useRuntimeConfig() const slugDefaultLength = +useRuntimeConfig().public.slugDefaultLength -export function nanoid(length: number = slugDefaultLength) { - return caseSensitive - ? customAlphabet('23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ', length) - : customAlphabet('23456789abcdefghjkmnpqrstuvwxyz', length) -} +export const nanoid = (length: number = slugDefaultLength) => customAlphabet('23456789abcdefghjkmnpqrstuvwxyz', length) export const LinkSchema = z.object({ id: z.string().trim().max(26).default(nanoid(10)), diff --git a/server/api/link/create.post.ts b/server/api/link/create.post.ts index 7797220..e3be9b1 100644 --- a/server/api/link/create.post.ts +++ b/server/api/link/create.post.ts @@ -3,6 +3,12 @@ import { LinkSchema } from '@/schemas/link' export default eventHandler(async (event) => { const link = await readValidatedBody(event, LinkSchema.parse) + const { caseSensitive } = useRuntimeConfig(event) + + if (!caseSensitive) { + link.slug = link.slug.toLowerCase() + } + const { cloudflare } = event.context const { KV } = cloudflare.env const existingLink = await KV.get(`link:${link.slug}`) diff --git a/server/middleware/1.redirect.ts b/server/middleware/1.redirect.ts index bafe5cc..524869c 100644 --- a/server/middleware/1.redirect.ts +++ b/server/middleware/1.redirect.ts @@ -19,13 +19,13 @@ export default eventHandler(async (event) => { const getLink = async (key: string) => await KV.get(`link:${key}`, { type: 'json', cacheTtl: linkCacheTtl }) - link = await getLink(slug) - - // fallback to lowercase slug if caseSensitive is false and the slug is not found const lowerCaseSlug = slug.toLowerCase() + link = await getLink(caseSensitive ? slug : lowerCaseSlug) + + // fallback to original slug if caseSensitive is false and the slug is not found if (!caseSensitive && !link && lowerCaseSlug !== slug) { - console.log('lowerCaseSlug fallback:', `slug:${slug} lowerCaseSlug:${lowerCaseSlug}`) - link = await getLink(lowerCaseSlug) + console.log('original slug fallback:', `slug:${slug} lowerCaseSlug:${lowerCaseSlug}`) + link = await getLink(slug) } if (link) {