之前用 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 的同志们可以参考下
1,完整的 code 有么,我看你在 github 上的没有新的路由的那部分。对
Weixin::Router.new(:type => "image")
这一段没懂哈;
2,rails 4 似乎有说如下,是不是说 4 开始要加 gem 才能这么轻松处理接收的 xml
Remove support for parsing XML parameters from request. If you still want to parse XML parameters, please install `actionpack-xml_parser' gem.
3,对于不同的请求 type,可以在逻辑代码里面用 send 不同的方法来区分,和通过路由来区分各有啥优劣
class DemoWeixin::Router
def initialize(type="text")
@message_type = type
end
def matches?(request)
xml_data = request.params[:xml]
if xml_data and xml_data.is_a?(Hash)
@message_type == request.params[:xml][:MsgType]
end
end
end
DemoWeixin::Application.routes.draw do
get "welcome/index"
get "message/io" => "message#auth"
#post "message/io" => "message#talk"
scope "/", via: :post do
#match "message/io" => "message#reply_text", constraints: lambda {|request| request.params[:xml].nil? }
#match "message/io" => "message#reply_image", constraints: lambda {|request| request.params[:xml] && request.params[:xml][:MsgType] == "text"}
match "message/io" => "message#reply_text", constraints: DemoWeixin::Router.new("text")
match "message/io" => "message#reply_image", constraints: DemoWeixin::Router.new("image")
match "message/io" => "message#reply_location", constraints: DemoWeixin::Router.new("location")
match "message/io" => "message#reply_link", constraints: DemoWeixin::Router.new("link")
match "message/io" => "message#reply_event", constraints: DemoWeixin::Router.new("event")
match "message/io" => "message#reply_music", constraints: DemoWeixin::Router.new("music")
match "message/io" => "message#reply_news", constraints: DemoWeixin::Router.new("news")
match "message/io" => "message#reply_news", constraints: lambda {|r| r.params}
end
root to: 'welcome#index'
end
#6 楼 @as181920 哦,那个我写在另外一个项目里面,可以看看这里https://github.com/edokeh/bajiao-weixin/blob/master/config/initializers/weixin_router.rb 这样做的好处嘛,一是可维护性更高,router 中的声明式代码肯定比普通命令式的代码更容易理解和修改 另外一点,如果用子方法的话,其实每个子方法并不是 Rails 的 action 方法,这样使用上会有些局限,比如不能为其中的某个子方法单独加 filter Rails4 不支持 XML 的 POST 了啊?我还没注意到,去看看先
@edokeh 请教一下楼主,像例如我用招行信用卡做完一比交易,然后招行的公众号可以直接推一条交易内容的信息给我,请问这个推的接口是怎么调用的...微信文档里面找不到啊...
我是用元编程处理这些代码的杂乱问题,写了有文章在这里:http://ruxpin.is-programmer.com/posts/39118.html
请教楼主一个问题,为什么使用 root to,而不是
post ':username', :to => 'weixin#method_a', :constraints => lambda { |request| request.params[:xml][:MsgType] == 'image' }
Rails4 remove 了 xml post。。。 http://my.oschina.net/wchen/blog/151476 https://github.com/rails/actionpack-xml_parser
#23 楼 @ruby_sky 我是用 rails4,加了了 actionpack-xml_parser gem,验证的 URL 填写的是http://example.com/weixin/show 验证通过,但是发消息都是走 POST http://example.com/weixin/showURL改为,肯定错误,随后我把验证 http://example.com/weixin/create ,通过,但是问题是没 POST,为什么会有两个 URL 微信不通常都说一个吗?谢谢。