Rails: วิธีใดที่ดีในการตรวจสอบความถูกต้องของลิงก์ (URL)


125

ฉันสงสัยว่าฉันจะตรวจสอบ URL ใน Rails ให้ดีที่สุดได้อย่างไร ฉันกำลังคิดว่าจะใช้นิพจน์ทั่วไป แต่ไม่แน่ใจว่านี่เป็นแนวทางปฏิบัติที่ดีที่สุดหรือไม่

และถ้าฉันจะใช้ regex มีใครแนะนำให้ฉันได้ไหม ฉันยังใหม่กับ Regex


ที่เกี่ยวข้อง: stackoverflow.com/questions/1805761/…
Jon Schneider

คำตอบ:


151

การตรวจสอบ URL เป็นงานที่ยุ่งยาก ยังเป็นคำขอที่กว้างมาก

คุณต้องการทำอะไรกันแน่? คุณต้องการตรวจสอบรูปแบบของ URL การมีอยู่หรืออะไร มีความเป็นไปได้หลายประการขึ้นอยู่กับสิ่งที่คุณต้องการทำ

นิพจน์ทั่วไปสามารถตรวจสอบความถูกต้องของรูปแบบของ URL แต่แม้แต่นิพจน์ทั่วไปที่ซับซ้อนก็ไม่สามารถมั่นใจได้ว่าคุณกำลังจัดการกับ URL ที่ถูกต้อง

ตัวอย่างเช่นหากคุณใช้นิพจน์ทั่วไปง่ายๆก็อาจปฏิเสธโฮสต์ต่อไปนี้

http://invalid##host.com

แต่จะอนุญาต

http://invalid-host.foo

นั่นคือโฮสต์ที่ถูกต้อง แต่ไม่ใช่โดเมนที่ถูกต้องหากคุณพิจารณา TLD ที่มีอยู่ แน่นอนวิธีแก้ปัญหาจะใช้ได้ถ้าคุณต้องการตรวจสอบชื่อโฮสต์ไม่ใช่โดเมนเนื่องจากชื่อต่อไปนี้เป็นชื่อโฮสต์ที่ถูกต้อง

http://host.foo

เช่นเดียวกับสิ่งต่อไปนี้

http://localhost

ตอนนี้ให้ฉันแก้ปัญหาบางอย่าง

หากคุณต้องการตรวจสอบโดเมนคุณต้องลืมเกี่ยวกับนิพจน์ทั่วไป ทางออกที่ดีที่สุดในขณะนี้คือ Public Suffix List ซึ่งเป็นรายการที่ Mozilla ดูแล ฉันสร้างห้องสมุดทับทิมที่จะแยกและตรวจสอบโดเมนกับสาธารณะรายการต่อท้ายและก็เรียกว่าPublicSuffix

หากคุณต้องการตรวจสอบความถูกต้องของรูปแบบของ URI / URL คุณอาจต้องการใช้นิพจน์ทั่วไป แทนที่จะค้นหาอย่างใดอย่างหนึ่งให้ใช้URI.parseวิธีRuby ในตัว

require 'uri'

def valid_url?(uri)
  uri = URI.parse(uri) && !uri.host.nil?
rescue URI::InvalidURIError
  false
end

คุณยังสามารถตัดสินใจที่จะกำหนดให้มีข้อ จำกัด มากขึ้น ตัวอย่างเช่นหากคุณต้องการให้ URL เป็น HTTP / HTTPS URL คุณสามารถทำให้การตรวจสอบถูกต้องมากขึ้น

require 'uri'

def valid_url?(url)
  uri = URI.parse(url)
  uri.is_a?(URI::HTTP) && !uri.host.nil?
rescue URI::InvalidURIError
  false
end

แน่นอนว่ามีการปรับปรุงมากมายที่คุณสามารถนำไปใช้กับวิธีนี้รวมถึงการตรวจสอบเส้นทางหรือโครงร่าง

สุดท้าย แต่ไม่ท้ายสุดคุณสามารถรวมรหัสนี้ไว้ในโปรแกรมตรวจสอบความถูกต้อง:

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

1
โปรดทราบว่าชั้นเรียนจะเป็นURI::HTTPShttps uris (เช่นURI.parse("https://yo.com").class => URI::HTTPS
ที

12
URI::HTTPSสืบทอดจากที่เป็นเหตุผลว่าทำไมผมใช้URI:HTTP kind_of?
Simone Carletti

1
วิธีแก้ปัญหาที่สมบูรณ์ที่สุดในการตรวจสอบ URL อย่างปลอดภัย
Fabrizio Regini

4
URI.parse('http://invalid-host.foo')คืนค่าจริงเนื่องจาก URI เป็น URL ที่ถูกต้อง โปรดทราบว่า.fooตอนนี้ TLD ถูกต้องแล้ว iana.org/domains/root/db/foo.html
Simone Carletti

1
@jmccartie โปรดอ่านโพสต์ทั้งหมด หากคุณสนใจเกี่ยวกับโครงร่างคุณควรใช้รหัสสุดท้ายที่มีการตรวจสอบประเภทด้วยไม่ใช่เฉพาะบรรทัดนั้น คุณหยุดอ่านก่อนจบโพสต์
Simone Carletti

101

ฉันใช้ซับในแบบจำลองของฉัน:

validates :url, format: URI::regexp(%w[http https])

ฉันคิดว่าดีพอและใช้งานง่าย ยิ่งไปกว่านั้นควรจะเทียบเท่าในทางทฤษฎีกับวิธีการของ Simone เนื่องจากใช้ regexp เดียวกันภายใน


17
น่าเสียดายที่'http://'ตรงกับรูปแบบด้านบน ดู:URI::regexp(%w(http https)) =~ 'http://'
David J.

15
url like http:fakeก็ใช้ได้เช่นกัน
nathanvda

54

ตามแนวคิดของ Simone คุณสามารถสร้างโปรแกรมตรวจสอบความถูกต้องของคุณเองได้อย่างง่ายดาย

class UrlValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    return if value.blank?
    begin
      uri = URI.parse(value)
      resp = uri.kind_of?(URI::HTTP)
    rescue URI::InvalidURIError
      resp = false
    end
    unless resp == true
      record.errors[attribute] << (options[:message] || "is not an url")
    end
  end
end

แล้วใช้

validates :url, :presence => true, :url => true

ในแบบจำลองของคุณ


1
ฉันควรใส่ชั้นเรียนนี้ที่ไหน ในการเริ่มต้น?
deb

3
ฉันอ้างจาก @gbc: "หากคุณวางโปรแกรมตรวจสอบความถูกต้องที่กำหนดเองไว้ในแอป / ตัวตรวจสอบความถูกต้องพวกเขาจะโหลดโดยอัตโนมัติโดยไม่จำเป็นต้องแก้ไขไฟล์ config / application.rb ของคุณ" ( stackoverflow.com/a/6610270/839847 ) โปรดทราบว่าคำตอบด้านล่างจาก Stefan Pettersson แสดงให้เห็นว่าเขาบันทึกไฟล์ที่คล้ายกันใน "app / validators" ด้วย
bergie3000

4
สิ่งนี้จะตรวจสอบว่า URL ขึ้นต้นด้วย http: // หรือ https: // ไม่ใช่การตรวจสอบ URL ที่ถูกต้อง
maggix

1
สิ้นสุดหากคุณสามารถจ่าย URL ให้เป็นทางเลือก: class OptionalUrlValidator <UrlValidator def validate_each (record, attribute, value) จะคืนค่า true if value.blank? return super end end
Dirty Henry

1
นี่ไม่ใช่การตรวจสอบที่ดี:URI("http:").kind_of?(URI::HTTP) #=> true
smathy

29

นอกจากนี้ยังมีอัญมณี validate_url (ซึ่งเป็นเพียงกระดาษห่อหุ้มที่ดีสำหรับAddressable::URI.parseการแก้ปัญหา)

เพียงแค่เพิ่ม

gem 'validate_url'

ให้กับคุณGemfileแล้วในแบบจำลองที่คุณทำได้

validates :click_through_url, url: true

@ ЕвгенийМасленковว่าอาจจะมีเพียงเช่นกันเพราะตามที่ถูกต้องของข้อมูลจำเพาะ แต่คุณอาจต้องการตรวจสอบgithub.com/sporkmonger/addressable/issues นอกจากนี้ในกรณีทั่วไปเราพบว่าไม่มีใครปฏิบัติตามมาตรฐานและใช้การตรวจสอบรูปแบบอย่างง่ายแทน
dolzenko

13

คำถามนี้มีคำตอบแล้ว แต่สิ่งที่ฉันเสนอวิธีแก้ปัญหาที่ฉันใช้

regexp ทำงานได้ดีกับ URL ทั้งหมดที่ฉันพบ วิธี setter คือการดูแลหากไม่มีการกล่าวถึงโปรโตคอล (สมมติว่า http: //)

และสุดท้ายเราจะพยายามดึงข้อมูลหน้า บางทีฉันควรยอมรับการเปลี่ยนเส้นทางไม่ใช่แค่ HTTP 200 OK เท่านั้น

# app/models/my_model.rb
validates :website, :allow_blank => true, :uri => { :format => /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$)/ix }

def website= url_str
  unless url_str.blank?
    unless url_str.split(':')[0] == 'http' || url_str.split(':')[0] == 'https'
        url_str = "http://" + url_str
    end
  end  
  write_attribute :website, url_str
end

และ...

# app/validators/uri_vaidator.rb
require 'net/http'

# Thanks Ilya! http://www.igvita.com/2006/09/07/validating-url-in-ruby-on-rails/
# Original credits: http://blog.inquirylabs.com/2006/04/13/simple-uri-validation/
# HTTP Codes: http://www.ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTPResponse.html

class UriValidator < ActiveModel::EachValidator
  def validate_each(object, attribute, value)
    raise(ArgumentError, "A regular expression must be supplied as the :format option of the options hash") unless options[:format].nil? or options[:format].is_a?(Regexp)
    configuration = { :message => I18n.t('errors.events.invalid_url'), :format => URI::regexp(%w(http https)) }
    configuration.update(options)

    if value =~ configuration[:format]
      begin # check header response
        case Net::HTTP.get_response(URI.parse(value))
          when Net::HTTPSuccess then true
          else object.errors.add(attribute, configuration[:message]) and false
        end
      rescue # Recover on DNS failures..
        object.errors.add(attribute, configuration[:message]) and false
      end
    else
      object.errors.add(attribute, configuration[:message]) and false
    end
  end
end

เรียบร้อยจริงๆ! ขอบคุณสำหรับข้อมูลของคุณมักจะมีหลายวิธีในการแก้ปัญหา มันยอดเยี่ยมมากเมื่อมีคนแบ่งปันของพวกเขา
jay

6
แค่อยากจะชี้ให้เห็นว่าตามคู่มือการรักษาความปลอดภัยรางคุณควรใช้ \ A และ \ z มากกว่า $ ^ ใน regexp นั้น
Jared

1
ฉันชอบมัน. คำแนะนำอย่างรวดเร็วในการทำให้โค้ดแห้งเล็กน้อยโดยการย้าย regex ไปยังตัวตรวจสอบความถูกต้องตามที่ฉันคิดว่าคุณต้องการให้มันสอดคล้องกันในทุกรุ่น โบนัส: จะช่วยให้คุณสามารถวางบรรทัดแรกภายใต้ validate_each
Paul Pettengill

จะเกิดอะไรขึ้นถ้า url ใช้เวลานานและหมดเวลา? ตัวเลือกใดที่ดีที่สุดในการแสดงข้อความแสดงข้อผิดพลาดการหมดเวลาหรือหากไม่สามารถเปิดหน้าได้
user588324

สิ่งนี้จะไม่ผ่านการตรวจสอบความปลอดภัยคุณกำลังทำให้เซิร์ฟเวอร์ของคุณโผล่ URL ตามอำเภอใจ
Mauricio

12

คุณยังสามารถลองใช้valid_url gem ซึ่งอนุญาต URL ที่ไม่มีสกีมตรวจสอบโซนโดเมนและชื่อโฮสต์ ip

เพิ่มลงใน Gemfile ของคุณ:

gem 'valid_url'

จากนั้นในรุ่น:

class WebSite < ActiveRecord::Base
  validates :url, :url => true
end

นี่เป็นสิ่งที่ดีมากโดยเฉพาะ URL ที่ไม่มีโครงร่างซึ่งเกี่ยวข้องกับคลาส URI อย่างน่าประหลาดใจ
Paul Pettengill

ฉันรู้สึกประหลาดใจกับความสามารถของอัญมณีนี้ในการขุดผ่าน URL ตาม IP และตรวจจับของปลอม ขอบคุณ!
The Whiz of Oz

10

แค่ 2 เซ็นต์ของฉัน:

before_validation :format_website
validate :website_validator

private

def format_website
  self.website = "http://#{self.website}" unless self.website[/^https?/]
end

def website_validator
  errors[:website] << I18n.t("activerecord.errors.messages.invalid") unless website_valid?
end

def website_valid?
  !!website.match(/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-=\?]*)*\/?$/)
end

แก้ไข: เปลี่ยน regex เพื่อให้ตรงกับ URL พารามิเตอร์


1
ขอบคุณสำหรับการป้อนข้อมูลของคุณเสมอดีที่จะเห็นการแก้ปัญหาที่แตกต่างกัน
jay

Btw regexp ของคุณจะปฏิเสธ URL ที่ถูกต้องพร้อมด้วยสตริงข้อความค้นหาเช่นhttp://test.com/fdsfsdf?a=b
MikDiet

2
เราใส่รหัสนี้ในการผลิตและยังคงได้รับการหมดเวลาในลูปที่ไม่มีที่สิ้นสุดบนบรรทัด. แมตช์ regex ไม่แน่ใจว่าทำไมเพียงแค่เตือนสำหรับ cornercases และชอบที่จะได้ยินความคิดของผู้อื่นว่าเหตุใดจึงเกิดขึ้น
toobulkeh

10

วิธีแก้ปัญหาที่เหมาะกับฉันคือ:

validates_format_of :url, :with => /\A(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w\.-]*)*\/?\Z/i

ฉันพยายามใช้ตัวอย่างที่คุณแนบมา แต่ฉันรองรับ url ดังนี้:

สังเกตการใช้ A และ Z เพราะถ้าคุณใช้ ^ และ $ คุณจะเห็นการรักษาความปลอดภัยคำเตือนนี้จาก Rails validators

 Valid ones:
 'www.crowdint.com'
 'crowdint.com'
 'http://crowdint.com'
 'http://www.crowdint.com'

 Invalid ones:
  'http://www.crowdint. com'
  'http://fake'
  'http:fake'

1
ลองใช้กับ"https://portal.example.com/portal/#". ใน Ruby 2.1.6 การประเมินค้าง
โปรเก่า

คุณคิดถูกในบางกรณีการแสดงออกปกตินี้ใช้เวลาแก้ไขตลอดไป :(
heriberto perez

1
เห็นได้ชัดว่าไม่มี regex ที่ครอบคลุมทุกสถานการณ์นั่นคือเหตุผลที่ฉันต้องใช้การตรวจสอบความถูกต้องง่ายๆ: validates: url, format: {with: URI.regexp}, if: Proc.new {| a | a.url.present? }
heriberto perez

5

เมื่อเร็ว ๆ นี้ฉันพบปัญหาเดียวกัน (ฉันต้องการตรวจสอบความถูกต้องของ URL ในแอป Rails) แต่ฉันต้องรับมือกับข้อกำหนดเพิ่มเติมของยูนิโคด URL (เช่นhttp://кц.рф) ...

ฉันค้นคว้าวิธีแก้ปัญหาสองสามข้อและพบสิ่งต่อไปนี้:

  • URI.parseสิ่งแรกและชี้ให้เห็นมากที่สุดคือการใช้ ตรวจสอบคำตอบโดย Simone Carletti สำหรับรายละเอียด ใช้งานได้ แต่ไม่ใช่สำหรับ URL แบบยูนิโคด
  • วิธีที่สองที่ฉันเห็นคือวิธีที่ Ilya Grigorik: http://www.igvita.com/2006/09/07/validating-url-in-ruby-on-rails/โดยทั่วไปเขาพยายามที่จะร้องขอไปยัง URL; ถ้าใช้งานได้ก็ใช้ได้ ...
  • วิธีที่สามที่ฉันพบ (และวิธีที่ฉันชอบ) เป็นวิธีการที่คล้ายกับURI.parseแต่ใช้addressableอัญมณีแทนURIstdlib แนวทางนี้มีรายละเอียดที่นี่: http://rawsyntax.com/blog/url-validation-in-rails-3-and-ruby-in-general/

ใช่ แต่Addressable::URI.parse('http:///').scheme # => "http"หรือAddressable::URI.parse('Съешь [же] ещё этих мягких французских булок да выпей чаю')เป็นที่ยอมรับอย่างสมบูรณ์จากมุมมองของ Addressable :(
smileart

4

นี่เป็นรุ่นที่ปรับปรุงของตรวจสอบโพสต์โดยเดวิดเจมส์ มันได้รับการตีพิมพ์โดยเบนจามิน Fleischer ในขณะที่ฉันผลักดันการปรับปรุงทางแยกซึ่งสามารถพบได้ที่นี่

require 'addressable/uri'

# Source: http://gist.github.com/bf4/5320847
# Accepts options[:message] and options[:allowed_protocols]
# spec/validators/uri_validator_spec.rb
class UriValidator < ActiveModel::EachValidator

  def validate_each(record, attribute, value)
    uri = parse_uri(value)
    if !uri
      record.errors[attribute] << generic_failure_message
    elsif !allowed_protocols.include?(uri.scheme)
      record.errors[attribute] << "must begin with #{allowed_protocols_humanized}"
    end
  end

private

  def generic_failure_message
    options[:message] || "is an invalid URL"
  end

  def allowed_protocols_humanized
    allowed_protocols.to_sentence(:two_words_connector => ' or ')
  end

  def allowed_protocols
    @allowed_protocols ||= [(options[:allowed_protocols] || ['http', 'https'])].flatten
  end

  def parse_uri(value)
    uri = Addressable::URI.parse(value)
    uri.scheme && uri.host && uri
  rescue URI::InvalidURIError, Addressable::URI::InvalidURIError, TypeError
  end

end

...

require 'spec_helper'

# Source: http://gist.github.com/bf4/5320847
# spec/validators/uri_validator_spec.rb
describe UriValidator do
  subject do
    Class.new do
      include ActiveModel::Validations
      attr_accessor :url
      validates :url, uri: true
    end.new
  end

  it "should be valid for a valid http url" do
    subject.url = 'http://www.google.com'
    subject.valid?
    subject.errors.full_messages.should == []
  end

  ['http://google', 'http://.com', 'http://ftp://ftp.google.com', 'http://ssh://google.com'].each do |invalid_url|
    it "#{invalid_url.inspect} is a invalid http url" do
      subject.url = invalid_url
      subject.valid?
      subject.errors.full_messages.should == []
    end
  end

  ['http:/www.google.com','<>hi'].each do |invalid_url|
    it "#{invalid_url.inspect} is an invalid url" do
      subject.url = invalid_url
      subject.valid?
      subject.errors.should have_key(:url)
      subject.errors[:url].should include("is an invalid URL")
    end
  end

  ['www.google.com','google.com'].each do |invalid_url|
    it "#{invalid_url.inspect} is an invalid url" do
      subject.url = invalid_url
      subject.valid?
      subject.errors.should have_key(:url)
      subject.errors[:url].should include("is an invalid URL")
    end
  end

  ['ftp://ftp.google.com','ssh://google.com'].each do |invalid_url|
    it "#{invalid_url.inspect} is an invalid url" do
      subject.url = invalid_url
      subject.valid?
      subject.errors.should have_key(:url)
      subject.errors[:url].should include("must begin with http or https")
    end
  end
end

โปรดสังเกตว่ายังมี HTTP URI แปลก ๆ ที่แยกวิเคราะห์เป็นที่อยู่ที่ถูกต้อง

http://google  
http://.com  
http://ftp://ftp.google.com  
http://ssh://google.com

นี่คือปัญหาสำหรับaddressableอัญมณีที่ครอบคลุมตัวอย่าง


3

ผมใช้การเปลี่ยนแปลงเล็กน้อยในการแก้ปัญหาดังกล่าวข้างต้น Lafeber ไม่อนุญาตให้ใช้จุดที่ติดต่อกันในชื่อโฮสต์ (เช่นอินสแตนซ์www.many...dots.com):

%r"\A(https?://)?[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]{2,6}(/.*)?\Z"i

URI.parseดูเหมือนว่าจะกำหนดคำนำหน้าแบบแผนซึ่งในบางกรณีอาจไม่ใช่สิ่งที่คุณต้องการ (เช่นหากคุณต้องการอนุญาตให้ผู้ใช้ของคุณสะกด URL ในรูปแบบต่างๆได้อย่างรวดเร็วเช่นtwitter.com/username)


2

ฉันใช้อัญมณี 'activevalidators'และใช้งานได้ดี (ไม่ใช่เฉพาะการตรวจสอบ URL)

คุณสามารถหาได้ที่นี่

ทุกอย่างได้รับการบันทึกไว้แล้ว แต่โดยทั่วไปเมื่อเพิ่มอัญมณีแล้วคุณจะต้องเพิ่มสองสามบรรทัดต่อไปนี้ในตัวเริ่มต้นพูดว่า: /config/environment/initializers/active_validators_activation.rb

# Activate all the validators
ActiveValidators.activate(:all)

(หมายเหตุ: คุณสามารถแทนที่: all by: url หรือ: อะไรก็ได้หากคุณต้องการตรวจสอบความถูกต้องของค่าบางประเภท)

แล้วย้อนกลับไปในโมเดลของคุณประมาณนี้

class Url < ActiveRecord::Base
   validates :url, :presence => true, :url => true
end

ตอนนี้รีสตาร์ทเซิร์ฟเวอร์และนั่นควรจะเป็น


2

หากคุณต้องการการตรวจสอบอย่างง่ายและข้อความแสดงข้อผิดพลาดที่กำหนดเอง:

  validates :some_field_expecting_url_value,
            format: {
              with: URI.regexp(%w[http https]),
              message: 'is not a valid URL'
            }

1

คุณสามารถตรวจสอบหลาย URL โดยใช้สิ่งต่อไปนี้

validates_format_of [:field1, :field2], with: URI.regexp(['http', 'https']), allow_nil: true

1
คุณจะจัดการ URL ที่ไม่มีโครงร่างอย่างไร (เช่น www.bar.com/foo)
Craig


1

เมื่อเร็ว ๆ นี้ฉันมีปัญหาเดียวกันนี้และฉันพบวิธีแก้ปัญหาสำหรับ URL ที่ถูกต้อง

validates_format_of :url, :with => URI::regexp(%w(http https))
validate :validate_url
def validate_url

  unless self.url.blank?

    begin

      source = URI.parse(self.url)

      resp = Net::HTTP.get_response(source)

    rescue URI::InvalidURIError

      errors.add(:url,'is Invalid')

    rescue SocketError 

      errors.add(:url,'is Invalid')

    end



  end

ส่วนแรกของเมธอด validate_url เพียงพอที่จะตรวจสอบความถูกต้องของรูปแบบ URL ส่วนที่สองจะทำให้แน่ใจว่ามี url อยู่โดยการส่งคำขอ


จะเกิดอะไรขึ้นถ้า url ชี้ไปยังทรัพยากรที่มีขนาดใหญ่มาก (เช่นหลายกิกะไบต์)
Jon Schneider

@JonSchneider หนึ่งสามารถใช้ http head request (เช่นที่นี่ ) แทน get.
wvengen

1

ฉันชอบที่จะจับคู่โมดูล URI เพื่อเพิ่มที่ถูกต้อง? วิธี

ภายใน config/initializers/uri.rb

module URI
  def self.valid?(url)
    uri = URI.parse(url)
    uri.is_a?(URI::HTTP) && !uri.host.nil?
  rescue URI::InvalidURIError
    false
  end
end

0

และเป็นโมดูล

module UrlValidator
  extend ActiveSupport::Concern
  included do
    validates :url, presence: true, uniqueness: true
    validate :url_format
  end

  def url_format
    begin
      errors.add(:url, "Invalid url") unless URI(self.url).is_a?(URI::HTTP)
    rescue URI::InvalidURIError
      errors.add(:url, "Invalid url")
    end
  end
end

จากนั้นinclude UrlValidatorในรุ่นใดก็ได้ที่คุณต้องการตรวจสอบความถูกต้องของ url รวมเพียงสำหรับตัวเลือก


0

การตรวจสอบความถูกต้องของ URL ไม่สามารถจัดการได้ง่ายๆโดยใช้นิพจน์ทั่วไปเนื่องจากจำนวนเว็บไซต์เพิ่มขึ้นเรื่อย ๆ และมีแผนการตั้งชื่อโดเมนใหม่ ๆ

ในกรณีของฉันฉันเพียงแค่เขียนโปรแกรมตรวจสอบความถูกต้องที่กำหนดเองเพื่อตรวจสอบการตอบสนองที่ประสบความสำเร็จ

class UrlValidator < ActiveModel::Validator
  def validate(record)
    begin
      url = URI.parse(record.path)
      response = Net::HTTP.get(url)
      true if response.is_a?(Net::HTTPSuccess)   
    rescue StandardError => error
      record.errors[:path] << 'Web address is invalid'
      false
    end  
  end
end

ฉันกำลังตรวจสอบpathคุณสมบัติของโมเดลของฉันโดยใช้record.path. ฉันยังส่งข้อผิดพลาดไปยังชื่อแอตทริบิวต์ที่เกี่ยวข้องโดยใช้record.errors[:path].

คุณสามารถแทนที่ด้วยชื่อแอตทริบิวต์ใดก็ได้

จากนั้นฉันก็เรียกตัวตรวจสอบความถูกต้องที่กำหนดเองในโมเดลของฉัน

class Url < ApplicationRecord

  # validations
  validates_presence_of :path
  validates_with UrlValidator

end

จะเกิดอะไรขึ้นถ้า url ชี้ไปยังทรัพยากรที่มีขนาดใหญ่มาก (เช่นหลายกิกะไบต์)
จอนชไนเดอร์

0

คุณสามารถใช้ regex สำหรับสิ่งนี้สำหรับฉันทำงานได้ดีอันนี้:

(^|[\s.:;?\-\]<\(])(ftp|https?:\/\/[-\w;\/?:@&=+$\|\_.!~*\|'()\[\]%#,]+[\w\/#](\(\))?)(?=$|[\s',\|\(\).:;?\-\[\]>\)])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.