Next.js
Next.js에서 한글 slug를 쓸 때 URL 복사가 깨지는 이유
한글 slug는 브라우저 주소창에서는 읽기 편하지만, 복사하면 퍼센트 인코딩된 긴 문자열이 된다. canonical URL도 같은 문제가 생긴다.
한글 slug를 쓰면 URL이 /posts/타입스크립트-입문 처럼 나와서 읽기 편하다. 그런데 이 URL을 복사해서 다른 곳에 붙이면 /posts/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9E%85%EB%AC%B8 같은 형태가 된다.
브라우저는 주소창에서 한글을 디코딩해서 보여주지만, 클립보드에는 인코딩된 값이 복사된다.
어디서 문제가 되는가
링크 공유: SNS나 메신저에 붙이면 긴 인코딩 문자열이 노출된다. 일부 플랫폼은 이를 URL로 인식하지 못하기도 한다.
canonical URL: <link rel="canonical"> 태그에 인코딩되지 않은 한글이 그대로 들어가면 검색엔진이 올바르게 처리하지 못할 수 있다.
RSS: RSS 피드의 <link> 요소에 한글이 들어가면 일부 리더에서 파싱 에러가 난다.
curl -s https://example.com/posts/타입스크립트-입문 | grep canonical
실제로 어떤 값이 출력되는지 확인한다.
Next.js에서 처리하는 방법
generateMetadata에서 canonical URL을 만들 때 encodeURIComponent를 써서 slug를 인코딩한다.
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { slug } = params;
const encodedSlug = encodeURIComponent(slug);
return {
alternates: {
canonical: `https://example.com/posts/${encodedSlug}`,
},
};
}
encodeURIComponent는 한글을 퍼센트 인코딩으로 바꾸지만, /는 건드리지 않는다.
slug 자체를 영문으로 쓰는 방법
근본적인 해결책은 slug를 처음부터 영문으로 만드는 것이다. 글 제목에서 slug를 자동 생성할 때 한글을 로마자로 변환하거나(한글 → hangeul), 영문 slug를 따로 입력하도록 한다.
import slugify from 'slugify';
// 한글 제목은 직접 영문 slug를 지정
const slug = 'typescript-intro'; // '타입스크립트-입문' 대신
영문 slug를 쓰면 복사 문제, canonical 문제, RSS 문제가 한 번에 해결된다. 단, 이미 한글 slug로 공개된 글이 있다면 redirect 처리가 필요하다.
// next.config.js
redirects: async () => [
{
source: '/posts/%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9E%85%EB%AC%B8',
destination: '/posts/typescript-intro',
permanent: true,
},
],
한글 URL이 보기 좋다는 이유만으로 선택하면 이런 복잡함이 뒤따른다는 걸 미리 알고 결정하는 게 낫다.