Rails 简单处理掉所有 Rails ActionController::RoutingError 的错误

huacnlee · 2014年09月10日 · 最后由 hw676018683 回复于 2014年10月09日 · 8244 次阅读
本帖已被管理员设置为精华贴

项目上线以后,难免都会遇到爬虫,或某些奇怪的东西扫描网站,然后我们的 production.log 就会出现很多这样的错误信息:

Started GET "/register.php" for 110.75.186.226 at 2013-05-23 05:47:32 +0800

ActionController::RoutingError (No route matches [GET] "/register.php"):
  actionpack (3.2.13) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
  actionpack (3.2.13) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call'
  railties (3.2.13) lib/rails/rack/logger.rb:32:in `call_app'
  railties (3.2.13) lib/rails/rack/logger.rb:16:in `block in call'
  activesupport (3.2.13) lib/active_support/tagged_logging.rb:22:in `tagged'
  railties (3.2.13) lib/rails/rack/logger.rb:16:in `call'
  actionpack (3.2.13) lib/action_dispatch/middleware/request_id.rb:22:in `call'
  rack (1.4.5) lib/rack/methodoverride.rb:21:in `call'
  rack (1.4.5) lib/rack/runtime.rb:17:in `call'
  activesupport (3.2.13) lib/active_support/cache/strategy/local_cache.rb:72:in `call'
  rack (1.4.5) lib/rack/lock.rb:15:in `call'
  rack-cache (1.2) lib/rack/cache/context.rb:136:in `forward'
  rack-cache (1.2) lib/rack/cache/context.rb:245:in `fetch'
  rack-cache (1.2) lib/rack/cache/context.rb:185:in `lookup'
  rack-cache (1.2) lib/rack/cache/context.rb:66:in `call!'
  rack-cache (1.2) lib/rack/cache/context.rb:51:in `call'
  railties (3.2.13) lib/rails/engine.rb:479:in `call'
  railties (3.2.13) lib/rails/application.rb:223:in `call'
  railties (3.2.13) lib/rails/railtie/configurable.rb:30:in `method_missing'

虽然表面上没有什么大问题,但是这种错误的请求打乱了我们的 Log,尤其是当你用了 exception_notification 这类东西做提醒的时候,你的日常工作将会被这些打乱(当然可以在提交前屏蔽 ActionController::RoutingError 的错误,那是另外回事)。

只需要简单几步就能处理好

routes.rb 的最后加上

match '*path', via: :all, to: 'home#error_404'

home_controller.rb 加上

def error_404
  render file: "#{Rails.root}/public/404.html", status: 404, layout: false
end

然后 Log 里面干净了:

Started HEAD "/register.php" for 127.0.0.1 at 2014-09-10 19:05:41 +0800
Processing by HomeController#error_404 as */*
  Rendered public/404.html (0.6ms)
Completed 404 Not Found in 10ms (Views:  10ms | ActiveRecord: 0.0ms)

我的解法是这样:

get '*unmatched_route', to: 'application#render_404!'

#1 楼 @ruby_sky 这样每个 Controller 都继承了这个 action,可能有些潜在问题。

#2 楼 @Rei 没有在 route.rb 暴露出去,目前还没想到其他潜在问题。

最麻烦的是 ArgumentError::InvalidByteSequence ... 不知有没有办法处理 原因是 Rack 层解析请求时候遇到非法的字符抛出,还没有到 Rails 的路由层呢

#4 楼 @jasl 对的,这个前段时间一直遇到,最后直接覆盖了 Rack::Utils ,同求靠谱方法。

有没有简单的的办法直接在 Nginx 直接干掉这些爬虫?

#5 楼 @small_fish__ 这个 Rack 和 Rails 两边相互推诿,Rails 那边认为是 Rack 应该处理这种情况,Rack 说这种事情跟他们无关

#5 楼 @small_fish__ #7 楼 @jasl rack-utf8_sanitizer 可以干掉这些非法字符。你说的 Rack::Utils,应该类似 escape_utils ... 它们不是一个事。

来一个测试,这里包含了非法字符 curl http://rails-bestpractices.com/search\?utf8\=%E2%9C%93\&search\=foo%E0\&commit\=Search 不要一直玩...!

#8 楼 @leekelby 忘记当初是否使用过这个 gem, 最后重写了 Rack::Utils.normalize_params,加入了一段异常捕捉。

#8 楼 @leekelby 我之前使用 utf8-cleaner 这个,作用不大 来尝试下你说的这个

#6 楼 @48hour 可以考虑过滤 Agent

#11 楼 @jasl 我们用了这个之后非法字符错误消失了 rack-utf8_sanitizer

#13 楼 @hooooopo ok 明天尝试一下

昨天我还处理了一个 Rails 4.1 以前升级 4.1 后 Cookie 异常的问题,之前 Ruby China 后台捕捉到很多 JSON::ParserError

A JSON::ParserError occurred in articles#show:

  795: unexpected token at '{I"session_id:ETI"%4caed1ded93646981589c00f1c56b926;'
  app/controllers/articles_controller.rb:17:in `show'

https://github.com/ruby-china/ruby-china/commit/492fa7f94e1f2f6d445a65fbe18ddbd9da29d3ca

#7 楼 @jasl 个人觉得是 Rack 的问题,padrino 也存在这个错误,为此我们还特意去改了 http_router

#13 楼 @hooooopo 表单里面提交的错误编码也可以过滤掉吗?

想滤掉这些非法访问最合适的办法是上一层 WAF,不想自己维护可以使用云 WAF,比如安全宝。。。

@huacnlee 这个办法赞,似乎也没啥副作用。

#20 楼 @hemslo 被攻击这类宝宝会立即把你卖了

@046569 本来就是用来清洗流量的,所以这类服务的信用也是很重要的,就好比把钱扔家里还是银行里,要是敢卖了就木有人敢用了。。。

23 楼 已删除

之前看,爬虫,都是爬 php 的,难道 php 就那么多漏洞?

弱弱的问下。。。

为什么要 ' *path '

直接' * ' 不行嘛?

if ::Rails.env.production? 
  match '*path', via: :all, to: 'home#error_404'
end

需要加上环境,否则 rails 4.2 的 /rails/mailers 没法用

#26 楼 @vkill 弱弱的问下。。。

为什么要 ' *path '

直接' * ' 不行嘛?

@linjunzhugg Please see 3.11 Route Globbing and Wildcard Segments

get 'photos/*other', to: 'photos#unknown' This route would match photos/12 or /photos/long/path/to/12, setting params[:other] to "12" or "long/path/to/12". The fragments prefixed with a star are called "wildcard segments"

#11 楼 @jasl 我的 https://github.com/lulalala/utf8-cleaner (fork) 會過濾掉 invalid characters

不错的技巧

需要 登录 后方可回复, 如果你还没有账号请 注册新账号