您可以在 Rack 中间件层阻止请求。您可以使用 gem (rack-attack),也可以构建自己的 Rack 中间件。
选项 1:机架攻击
https://github.com/kickstarter/rack-attack
如果你想采用 rack-attack 方式,在安装之后,你可以使用如下配置:
# config/initializers/rack-attack.rb
class Rack::Attack
blacklist("block referer spam") do |request|
spammers = [/co\.lumb\.co/, /darodar/]
spammers.find { |spammer| request.referer =~ spammer }
end
end
由于我们喜欢测试,因此您应该先编写以下测试,然后再实施解决方案(使用 RSpec 请求规范):
# spec/requests/referer_spam_block_spec.rb
require "rails_helper"
describe "Referer blacklist", type: :request do
describe "referer spam" do
it "is blocked" do
spammers = ["http://co.lumb.co/", "http://forum.topic56809347.darodar.com/"]
spammers.each do |spammer|
get root_path, {}, { "HTTP_REFERER" => spammer }
expect(response).to be_forbidden
end
end
end
describe "regular referer" do
it "is not blocked" do
get root_path, {}, { "HTTP_REFERER" => "google.com" }
expect(response).to be_ok
end
end
describe "direct request" do
it "is not blocked" do
get root_path
expect(response).to be_ok
end
end
end
选项 2:自定义中间件
我还没有实现这个选项(我使用了 rack-attack),但是这里有一个关于 Rack 中间件应该如何工作的粗略想法(注意:我没有测试这个代码):
# lib/referer_spam_blocker.rb
class RefererSpamBlocker
SPAMMERS = [/co\.lumb\.co/, /darodar/]
def initialize(app)
@app = app
end
def call(env)
if blacklisted?(env)
forbidden
else
@app.call(env)
end
end
private
def blacklisted?(env)
!SPAMMERS.find { |spammer| env["HTTP_REFERER"] =~ spammer }.empty?
end
def forbidden
[403, {'Content-Type' => 'text/plain'}, ["Forbidden\n"]]
end
end
然后您可以通过将其添加到 config/application.rb 来配置 Rails 以使用它
config.middleware.use RefererSpamBlocker
更多关于如何编写 Rack 中间件的细节在这里:
http://railscasts.com/episodes/151-rack-middleware
奖金
如果您希望能够在不更改代码的情况下更改您阻止的内容,您可以使用 ENV 变量而不是硬编码垃圾邮件发送者。