之前用 Rails 弄过微信 API,无比轻松,几十行代码就能搭建一个简单的接口 不过要折腾得大一点的时候,发现代码组织上会比较麻烦,比如接口要实现这样的功能:如果发送 @+字符串,返回消息 A,如果发送图片,返回消息 B,发送其他文本,返回消息 C,这时候代码可能会这样
def create
query_type = params[:xml][:MsgType]
if query_type == "image"
do_method_b
elsif query_type == "text"
query = params[:xml][:Content]
if query.start_with? "@"
do_method_a
else
do_method_c
end
end
end
可以看到大量的逻辑堆在一个方法里面,即便用子方法切开,看起来也很乱。如果能够像 route 一样,根据请求的不同,由不同的 Controller 来处理的话,代码会清晰很多。我翻了下 route 的 API,发现还真能这样做,constraints 参数可以根据 request 的不同来决定路由
scope :path => "/weixin", :via => :post do
root :to => 'weixin#method_a', :constraints => lambda { |request| request.params[:xml][:MsgType] == 'image' }
root :to => 'weixin#method_b', :constraints => lambda { |request| request.params[:xml][:MsgType] == 'text' && request.params[:xml][:Content].start_with?('@') }
root :to => 'weixin#method_c', :constraints => lambda { |request| request.params[:xml][:MsgType] == 'text' }
end
这样看上去就清晰多了,如果嫌后面的 lambda 还是太繁琐,可以用一个 class 再稍微封装一下,比如我现在封装后的代码是这样
scope :path => "/weixin", :via => :post do
root :to => 'weixin#method_a', :constraints => Weixin::Router.new(:type => "image")
root :to => 'weixin#method_b', :constraints => Weixin::Router.new(:type => "text", :content => /^@/)
root :to => 'weixin#method_c', :constraints => Weixin::Router.new(:type => "text")
end
共同折腾微信 API 的同志们可以参考下