programing

Rails: 링크(URL)를 검증하는 좋은 방법은 무엇입니까?

powerit 2023. 7. 17. 21:29
반응형

Rails: 링크(URL)를 검증하는 좋은 방법은 무엇입니까?

레일즈에서 URL을 어떻게 검증하는 것이 가장 좋을지 궁금합니다.정규 표현을 사용하려고 했는데 이게 최선의 방법인지 모르겠어요.

그리고, 만약 제가 정규식을 사용한다면, 누가 저에게 하나 제안해주실 수 있나요?나는 아직 Regex에 익숙하지 않습니다.

URL의 유효성을 검사하는 것은 까다로운 작업입니다.그것은 또한 매우 광범위한 요청입니다.

정확히 무엇을 하고 싶습니까?URL 형식, 존재 또는 무엇을 검증하시겠습니까?당신이 하고 싶은 일에 따라 몇 가지 가능성이 있습니다.

정규식은 URL 형식의 유효성을 검사할 수 있습니다.그러나 복잡한 정규식도 유효한 URL을 처리할 수 없습니다.

예를 들어 간단한 정규식을 사용하면 다음 호스트가 거부될 수 있습니다.

http://invalid##host.com

하지만 그것은 허락할 것입니다.

http://invalid-host.foo

이는 유효한 호스트이지만 기존 TLD를 고려할 때 유효한 도메인은 아닙니다.실제로 솔루션은 도메인이 아닌 호스트 이름의 유효성을 확인하려는 경우 작동합니다. 도메인이 유효한 호스트 이름이기 때문입니다.

http://host.foo

다음 것과 마찬가지로

http://localhost

이제, 몇 가지 해결책을 드리겠습니다.

도메인의 유효성을 검사하려면 정규식을 잊어야 합니다.현재 사용 가능한 최고의 솔루션은 Mozilla가 관리하는 목록인 공개 접미사 목록입니다.공용 접미사 목록에 대한 도메인을 분석하고 검증하기 위해 루비 라이브러리를 만들었습니다. 이 라이브러리는 공용 접미사 목록이라고 합니다.

URI/URL 형식의 유효성을 검사하려면 정규식을 사용해야 합니다.된 Ruby 검를색는대내장신 Ruby 다니합사를 하세요.URI.parse방법.

require 'uri'

def valid_url?(uri)
  uri = URI.parse(uri) && uri.host.present?
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.present?
rescue URI::InvalidURIError
  false
end

물론, 이 방법에 적용할 수 있는 개선 사항은 경로 또는 계획 확인을 포함하여 매우 많습니다.

마지막으로, 이 코드를 검증자로 패키지화할 수도 있습니다.

class HttpUrlValidator < ActiveModel::EachValidator

  def self.compliant?(value)
    uri = URI.parse(value)
    uri.is_a?(URI::HTTP) && uri.host.present?
  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

최신 URI 버전(예: 0.12.1)에 대한 참고 사항

.present?/.blank?를 사용하는 대신 호스트를 검증하는 더 정확한 방법이 될 것입니다.uri.host.nil?아니면 그냥if uri.host이전 버전(예: URI v 0.11).

URI.parse("https:///394")의 예:

  • 버전 새URI 전버(0.12),host문자열을 하고, " " " " 를 반환합니다./394경로됩니다. HTTPS >#<URI::HTTPS https://394>
  • 버전 이전 URI 버전(0.11),host문자열을 하고, " " " " 를 반환합니다./394길되도합니다기이. HTTPS >#<URI::HTTPS https:/394>

저는 모델 내부에 하나의 라이너를 사용합니다.

validates :url, format: URI::DEFAULT_PARSER.make_regexp(%w[http https])

저는 사용하기에 충분하고 간단하다고 생각합니다.또한 내부적으로 매우 동일한 regexp를 사용하기 때문에 이론적으로 Simone의 방법과 동등해야 합니다.

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

당신 모델에서.

validate_url gem도 있습니다(이것은 단지 좋은 포장지일 뿐입니다).Addressable::URI.parse해결책).

그냥 추가

gem 'validate_url'

의 신에게에.Gemfile그리고 모델에서 당신은 할 수 있습니다.

validates :click_through_url, url: true

이 질문에는 이미 답이 나와 있습니다만, 도대체 제가 사용하고 있는 해결책을 제안합니다.

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

저에게 효과적인 솔루션은 다음과 같습니다.

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

당신이 첨부한 예시 중 일부를 사용하려고 했지만, 저는 그렇게 url을 지원하고 있습니다.

^과 $를 사용하면 레일 검사기에서 이 경고 보안을 볼 수 있으므로 A와 Z를 사용합니다.

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

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

또한 valid_url gem을 사용하여 체계 없이 URL을 허용하고 도메인 영역 및 IP-hostname을 확인할 수 있습니다.

Gem 파일에 추가:

gem 'valid_url'

모델에서 다음과 같습니다.

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

그냥 내 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

편집: 매개 변수 URL과 일치하도록 정규식이 변경되었습니다.

함). URL의 사항( Rails URL(Rails URL))을 해결해야 . 하지만 유니코드 URL의 추가 요구 사항(예:http://кц.рф)...

몇 가지 솔루션을 조사한 결과 다음과 같은 사실을 알게 되었습니다.

  • 첫 번째이자 가장 많이 제안되는 것은 사용하는 것입니다.URI.parse자세한 내용은 Simone Carletti의 답변을 확인하십시오.이것은 정상적으로 작동하지만 유니코드 URL에는 작동하지 않습니다.
  • 제가 본 두 번째 방법은 Ilya Grigorik의 방법입니다: http://www.igvita.com/2006/09/07/validating-url-in-ruby-on-rails/ 기본적으로, 그는 URL에 요청을 하려고 합니다; 만약 그것이 효과가 있다면, 그것은 유효합니다...
  • 세 제가은 제가찾세그방은법번째다방다음니접유법입근법사과한선은는제호하가고리▁to▁similar▁i▁the▁approach은그다▁an니)▁is제접▁method입다and▁third가▁(유▁i▁one▁the▁prefer음법근▁found사한과찾과 비슷한 방법입니다.URI.parse하지만 그것을 사용하는 것.addressable 대신 URIstdlib. 접근 방식은 http://rawsyntax.com/blog/url-validation-in-rails-3-and-ruby-in-general/ 에서 자세히 설명합니다.

David James가 게시한 검증자의 업데이트된 버전입니다.이 책은 벤자민 플라이셔에 의해 출판되었습니다.그러던 중, 저는 여기서 찾을 수 있는 업데이트된 포크를 밀었습니다.

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

여기 예시를 다루는 보석에 대한 이슈가 있습니다.

나는 위의 고무 용액에 약간 변형을 사용합니다.호스트 이름에서 연속적인 점을 허용하지 않습니다(예: 의 경우).www.many...dots.com):

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

URI.parse 철자할 수 을 빨리 철자할 수 있도록 ) 스킴 접두사를 해야 하는 것 .twitter.com/username)

나는 '능동적인 유효성 검사기' 보석을 사용해 왔고 그것은 꽤 잘 작동합니다(URL 유효성 검사뿐만 아니라).

여기서 찾을 수 있습니다.

모두 문서화되어 있지만 기본적으로 보석이 추가되면 이니셜라이저에 /config/environments/initializers/active_validators_activation.rb와 같은 몇 줄을 추가할 수 있습니다.

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

(참고: 특정 유형의 값만 확인하려는 경우 :all by :url 또는 :what로 대체할 수 있습니다.)

그리고 다시 당신의 모델로 돌아가서 이런 것.

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

이제 서버를 다시 시작하면 됩니다.

단순 유효성 검사 및 사용자 지정 오류 메시지를 원하는 경우:

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

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

다음과 같은 방법을 사용하여 여러 URL의 유효성을 검사할 수 있습니다.

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

https://github.com/perfectline/validates_url 당신에게 거의 모든 것을 해줄 멋지고 간단한 보석입니다.

최근에 저는 같은 문제를 겪었고 유효한 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이 존재하는지 확인합니다.

그리고 모듈로서

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 UrlValidatorURL의 유효성을 검사하려는 모든 모델에서.옵션을 포함해서요.

웹 사이트 수가 계속 증가하고 새 도메인 이름 지정 체계가 계속 나오기 때문에 정규식을 사용하여 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

당신은 이것에 정규식을 사용할 수 있습니다. 저는 이것이 잘 작동합니다.

(^|[\s.:;?\-\]<\(])(ftp|https?:\/\/[-\w;\/?:@&=+$\|\_.!~*\|'()\[\]%#,]+[\w\/#](\(\))?)(?=$|[\s',\|\(\).:;?\-\[\]>\)])

URI::regexp(%w[http https])사용되지 않으므로 사용해서는 안 됩니다.

대신 사용URI::DEFAULT_PARSER.make_regexp(%w[http https])

단순성 유지:

validates :url, format: %r{http(s)://.+}

HTTPS의 유효성을 검사하려면 다음을 사용할 수 있습니다.

require "uri"

class HttpsUrlValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless valid_url?(value)
      record.errors[attribute] << "is not a valid URL"
    end
  end

  private

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

모델에서 다음과 같은 용도:

validates :website_url, presence: true, https_url: true

언급URL : https://stackoverflow.com/questions/7167895/rails-whats-a-good-way-to-validate-links-urls

반응형