Chuyển đến nội dung chính
cutty.dev
All posts

Auto-prefix URL — một chi tiết nhỏ giúp tiết kiệm từng phút giây

cutty.dev nhận diện được khi bạn dán địa chỉ mà không có https:// và tự động thêm nó vào. Nghe có vẻ tầm thường, nhưng thực tế đó là sự khác biệt giữa việc xong trong hai giây và việc phải nhấn 'thử lại'.

Bạn nhập vào biểu mẫu allegro.pl. Bạn nhấp chuột. Và sao nữa?

Trong hầu hết các trình rút gọn link, tại thời điểm này bạn sẽ nhận được một thông báo lỗi. Kiểu như "đây không phải là URL hợp lệ". Bởi vì thiếu https:// ở phía trước. Vì vậy, bạn quay lại, thêm giao thức vào, nhấp lại một lần nữa, và chỉ đến lúc này bạn mới có liên kết rút gọn của mình.

cutty.dev không làm điều đó. Nó chỉ đơn giản là tự thêm https:// vào và tiếp tục như chưa có chuyện gì xảy ra.

Tôi biết nghe có vẻ như vậy. Giống như một tính năng vốn dĩ khó lòng xứng đáng với cả một đoạn văn, chưa nói đến việc là cả một bài viết. Tuy nhiên, tôi vẫn đang ngồi đây và viết về nó, bởi vì chính chi tiết nhỏ nhặt này lại là một bản tuyên ngôn nhỏ của riêng tôi về cách mà tôi tư duy trong việc xây dựng công cụ auto-prefix URL cũng như tất cả những tiện ích vô hình còn lại.

Hai giây so với hai mươi giây

Hãy cùng tính toán nào. Thực sự, hãy dựa vào những con số, vì nếu không thì đó chỉ là lời nói suông.

Lộ trình thứ nhất: dán vào, có liên kết, đóng cửa sổ. Hai giây. Có thể là ba giây.

Lộ trình thứ hai: bạn dán vào, lỗi, đọc thông báo (mất một hoặc hai giây để hiểu chuyện gì đang xảy ra), viết thêm giao thức, nhấn lại một lần nữa, và chỉ đến lúc này mới là link. Mười lăm, hai mươi giây. Cộng thêm khoảnh khắc khó chịu nhỏ nhoi đó, cái tiếng thầm thì "à đúng rồi, giao thức", thứ mà riêng lẻ thì chẳng tốn bao nhiêu nhưng lại tích tụ dần.

Và bây giờ hãy nhân con số đó với số lần bạn dán một địa chỉ nào đó trong một tháng. Với tôi là hàng chục lần. Với một người quản lý các liên kết chuyên nghiệp — là hàng trăm lần. Đột nhiên, chi tiết "vốn chẳng đáng kể" này tích tụ lại thành nhiều phút mỗi tháng. Tính trên mỗi người.

Đây chính là phép toán mà hầu hết mọi người thường bỏ qua, bởi vì mỗi trường hợp đơn lẻ đều có vẻ quá nhỏ để đáng để bận tâm.

Thực sự có gì ở bên dưới

Cơ chế này rất đơn giản và tôi không hề che giấu điều đó. Bạn dán văn bản vào trường nhập liệu. Trước khi bất cứ thứ gì được gửi lên máy chủ, một đoạn JavaScript sẽ kiểm tra xem nội dung bạn đã nhập có bắt đầu bằng một giao thức nào đó không — http://, https://, ftp://, mailto:, bất cứ thứ gì. Nếu nó không bắt đầu bằng các giao thức này, hệ thống sẽ mặc định rằng bạn đang muốn nói đến một tên miền thông thường và sẽ tự động thêm https:// vào phía trước.

Trong thực tế:

  • allegro.pl chuyển thành https://allegro.pl
  • github.com/twoj-profil/projekt thành https://github.com/twoj-profil/projekt
  • www.gazeta.pl thành https://www.gazeta.pl

Và nếu giao thức đã có sẵn ở đó, dù có kỳ lạ đến đâu, hệ thống cũng không ghi đè lên nó. Nó sẽ để nguyên và tiếp tục kiểm tra xem nên xử lý thế nào. http://example.com được thông qua (được cho phép). ftp://example.com bị loại bỏ, vì chúng ta chỉ chấp nhận http và https. Còn javascript:alert(1) sẽ bị loại ngay lập tức, vì đó không phải là một địa chỉ, mà là một nỗ lực chèn thứ gì đó độc hại (XSS cổ điển, xin cảm ơn, không nhé).

Tại sao tôi có cái này, còn một nửa thị trường thì không

Ở đây trở nên thú vị, vì câu trả lời hơi buồn cười một chút.

Cách tiêu chuẩn để kiểm tra tính hợp lệ của địa chỉ trong trình duyệt là hàm khởi tạo new URL(string). Và hàm khởi tạo này rất khắt khe. Không khoan nhượng. Nếu không có giao thức — nó sẽ báo lỗi. new URL("allegro.pl") sẽ chỉ trả về cho bạn một TypeError và thế thôi.

Và bạn biết không? Đây là một hành vi chính xác. Đối với đại đa số các ứng dụng, đó chính xác là những gì bạn muốn. Nhưng trong một biểu mẫu rút gọn liên kết, nơi con người sao chép địa chỉ từ thanh trình duyệt hoặc từ tin nhắn của ai đó, sự cứng nhắc này biến từ một lợi thế thành một trở ngại. Đột nhiên, một công cụ vốn dĩ để giúp bạn tiết kiệm thời gian lại bắt bạn phải sửa lại những gì mà lẽ ra nó đã có thể hiểu hoàn hảo.

Cách khắc phục điều này chỉ mất đúng vài dòng:

function sanitizeUrl(input) {
  const trimmed = input.trim();
  const hasProtocol = /^[a-z][a-z0-9+.-]*:/i.test(trimmed);
  const normalized = hasProtocol ? trimmed : "https://" + trimmed;
  // dalej leci normalna walidacja przez new URL(normalized)
}

Năm dòng code. Ít hơn mười mấy giây ma sát mỗi ngày, dành cho bất kỳ ai thường xuyên dán các địa chỉ. Thành thật mà nói, tôi không hiểu tại sao điều này không trở thành tiêu chuẩn ở mọi nơi. Tôi nghi ngờ rằng vấn đề là vì "URL constructor cứ thế hoạt động thôi" và chẳng ai muốn đụng vào nó cả. Đó là do quán tính, chứ không phải do ác ý.

Một chú thích nhỏ về ý nghĩa của từ "thông thường"

Bởi vì câu chuyện với new URL() này là một ví dụ tuyệt vời cho một vấn đề rộng lớn hơn. Rất nhiều thứ trong phần mềm vốn được coi là "cách làm chuẩn" thực chất lại là "kết quả từ các thiết lập mặc định của một thư viện nào đó mà không ai hề nghi ngờ". Chế độ nghiêm ngặt (strict mode) của constructor không phải là quyết định của các nhà thiết kế cutty hay đối thủ cạnh tranh — đó là quyết định của những tác giả đặc tả URL, được đưa ra trong một ngữ cảnh hoàn toàn khác, dành cho những mục đích sử dụng hoàn toàn khác.

Và sau đó toàn bộ thị trường thừa kế lựa chọn mặc định này và gọi nó là "tiêu chuẩn". Tôi có cảm giác rằng những sản phẩm tốt nhất được sinh ra chính tại những nơi mà ai đó đã dừng lại và tự hỏi: chờ đã, liệu hành vi này thực sự phục vụ người dùng của tôi, hay chỉ phục vụ thư viện của tôi? Thông thường câu trả lời là: phục vụ thư viện. Và khi đó, thật xứng đáng để dành ra năm dòng code để chuyển hướng về phía con người.

Có nhiều chi tiết nhỏ hơn những gì ta thấy

Auto-prefix chỉ là một trong nhiều yếu tố như vậy mà bạn sẽ không tìm thấy trong bất kỳ danh sách tính năng nào. Bởi vì nếu liệt kê chúng ở đó, mỗi cái riêng lẻ trông sẽ có vẻ nhỏ bé đến nực cười:

  • cắt bỏ khoảng trắng trước khi xác thực, để một khoảng trắng vô tình ở cuối địa chỉ được dán không làm hỏng mọi thứ
  • giữ lại neo (anchor), nghĩa là #section trong https://example.com/page#section không bị mất sau khi rút gọn
  • các tham số truy vấn (?utm_source=test) được giữ nguyên vẹn, không có gì bị cắt bỏ giữa chừng
  • các tên miền có ký tự tiếng Ba Lan, źdźbło.pl, tự động chuyển sang punycode
  • các chữ cái tiếng Ba Lan trong phần đuôi tùy chỉnh được chuyển thành ASCII (różowy-link trở thành rozowy-link)
  • các giao thức không an toàn — javascript:, data:, file: — bị chặn với một thông báo cụ thể, dễ hiểu

(Dự kiến sẽ có tính năng tự động chuyển đổi http:// thành https:// khi máy chủ đích hỗ trợ mã hóa. Tính năng này hiện vẫn chưa hoạt động trực tiếp, vì vậy tôi sẽ không giả vờ rằng nó đã xong.)

Mỗi chi tiết này đều giúp ai đó tiết kiệm được năm, mười, ba mươi giây và một tiếng thở dài. Đứng riêng lẻ thì không là gì cả. Cùng nhau, chúng tạo nên sự khác biệt giữa "chạy ổn" và "tôi thích sử dụng nó".

Những gì tôi muốn làm thêm

Danh sách những điều mong ước trong tương lai, vì việc nghĩ về chúng đơn giản là mang lại cho tôi niềm vui:

  • dán thông minh — phát hiện địa chỉ ẩn trong câu và trích xuất riêng URL ra khỏi các từ
  • dán hàng loạt — danh sách các địa chỉ, mỗi địa chỉ một dòng, và ngay lập tức tạo ra các liên kết rút gọn riêng biệt cho từng cái
  • gợi ý phần đuôi — dựa trên tiêu đề của trang đích để đề xuất ba slug thương hiệu để lựa chọn
  • xem trước Open Graph ngay sau khi dán, ngay cả trước khi bạn nhấn "rút gọn"

Mỗi thứ trong số này lại là một "hàm năm dòng trông có vẻ chẳng là gì". Và tất cả hợp lại? Đó chính là ranh giới giữa một công cụ ở mức tạm ổn, và một công cụ mà bạn sử dụng hàng ngày mà không cần suy nghĩ. Nếu bạn muốn thấy cách nó hoạt động ngay bây giờ, hãy dán bất cứ thứ gì không có giao thức vào cutty.devallegro.pl, github.com, news.ycombinator.com — và thấy rằng nó không hề gây khó khăn gì cho bạn.

Cuối cùng, một chút cá nhân

Tôi đã từng nghĩ lâu rồi rằng các sản phẩm chiến thắng nhờ những tính năng lớn lao. Một thứ gì đó ấn tượng duy nhất có thể trình chiếu trên một slide và khiến mọi người phải viết về nó. Và đúng vậy, đôi khi thực tế là như thế.

Nhưng càng xây dựng cutty lâu hơn, tôi càng cảm thấy mạnh mẽ rằng lòng trung thành của người dùng được hình thành ở một nơi khác — trong hàng trăm micro giây mà không ai nhận ra một cách có ý thức. Bạn không nhớ rằng công cụ đã tự động thêm https:// cho bạn. Bạn chỉ nhớ ấn tượng chung rằng "dùng cái này thấy khá ổn", "không gây khó chịu". Ấn tượng đó không tự nhiên mà có. Nó được tạo nên từ hàng chục quyết định chỉ vỏn vẹn năm dòng, mà nếu đứng riêng lẻ, sẽ không ai dám bảo vệ chúng là "xứng đáng với thời gian bỏ ra".

Có lẽ đó chính là bản chất của nghề thủ công. Không phải nằm ở một bước đi lớn lao nào cả, mà nằm ở sự kiên trì để hết lần này đến lần khác luôn đứng về phía người dùng khi họ điền biểu mẫu — ngay cả khi nó chỉ liên quan đến vỏn vẹn hai giây ngắn ngủi. Còn bạn thì sao? Điều gì gần đây đã làm bạn khó chịu trong một công cụ nào đó, nhỏ nhặt đến mức chẳng buồn thừa nhận? Bởi vì thông thường, chính tại những điểm đó mới là nơi có những công việc tuyệt vời nhất đang chờ được thực hiện.