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.
This commit is contained in:
ccbikai 2024-12-25 12:15:00 +08:00
parent af5724f3c1
commit 8d1bf6a451
5 changed files with 24 additions and 11 deletions

View file

@ -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.

View file

@ -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`.

View file

@ -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)),

View file

@ -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}`)

View file

@ -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) {