Xác thực một URL là một công việc khó khăn. Đó cũng là một yêu cầu rất rộng.
Chính xác thì bạn muốn làm gì? Bạn có muốn xác thực định dạng của URL, sự tồn tại hoặc những gì? Có một số khả năng, tùy thuộc vào những gì bạn muốn làm.
Biểu thức chính quy có thể xác thực định dạng của URL. Nhưng ngay cả một biểu thức chính quy phức tạp cũng không thể đảm bảo bạn đang xử lý một URL hợp lệ.
Chẳng hạn, nếu bạn lấy một biểu thức chính quy đơn giản, nó có thể sẽ từ chối máy chủ sau
http://invalid##host.com
nhưng nó sẽ cho phép
http://invalid-host.foo
đó là một máy chủ hợp lệ, nhưng không phải là một miền hợp lệ nếu bạn xem xét các TLD hiện có. Thật vậy, giải pháp sẽ hoạt động nếu bạn muốn xác thực tên máy chủ, không phải tên miền vì tên sau là tên máy chủ hợp lệ
http://host.foo
cũng như sau đây
http://localhost
Bây giờ, hãy để tôi cung cấp cho bạn một số giải pháp.
Nếu bạn muốn xác thực một tên miền, thì bạn cần quên đi các biểu thức thông thường. Giải pháp tốt nhất hiện có là Danh sách Suffix công khai, một danh sách được duy trì bởi Mozilla. Tôi đã tạo một thư viện Ruby để phân tích và xác thực các tên miền theo Danh sách Suffix công khai và nó được gọi là PublicSuffix .
Nếu bạn muốn xác thực định dạng của URI / URL, thì bạn có thể muốn sử dụng các biểu thức thông thường. Thay vì tìm kiếm một cái, hãy sử dụng URI.parse
phương thức Ruby tích hợp .
require 'uri'
def valid_url?(uri)
uri = URI.parse(uri) && !uri.host.nil?
rescue URI::InvalidURIError
false
end
Bạn thậm chí có thể quyết định làm cho nó hạn chế hơn. Ví dụ: nếu bạn muốn URL là URL HTTP / HTTPS, thì bạn có thể xác thực chính xác hơn.
require 'uri'
def valid_url?(url)
uri = URI.parse(url)
uri.is_a?(URI::HTTP) && !uri.host.nil?
rescue URI::InvalidURIError
false
end
Tất nhiên, có rất nhiều cải tiến bạn có thể áp dụng cho phương pháp này, bao gồm kiểm tra đường dẫn hoặc sơ đồ.
Cuối cùng nhưng không kém phần quan trọng, bạn cũng có thể đóng gói mã này vào trình xác nhận:
class HttpUrlValidator < ActiveModel::EachValidator
def self.compliant?(value)
uri = URI.parse(value)
uri.is_a?(URI::HTTP) && !uri.host.nil?
rescue URI::InvalidURIError
false
end
def validate_each(record, attribute, value)
unless value.present? && self.class.compliant?(value)
record.errors.add(attribute, "is not a valid HTTP URL")
end
end
end
# in the model
validates :example_attribute, http_url: true