关于这样一个头HTTP_X_HTTP_METHOD_OVERRIDE

如何从 Flex3.2 调用 Rails2.3.2 的 Restful API?

所谓 Restful API, 简单的说就是利用已有的四个 HTTP 动作实现对资源的四种操作:

  • GET 获取
  • POST 创建
  • PUT 更新
  • DELETE 删除

在这里对 REST 不作更详尽的解释, 相关资料网上有很多, 争议更多. 我们暂且不管这些争论(包括作者自己也在争论), 单从纯技术角度来看, 这种方式对于我们常见的 CRUD 操作实在是再方便不过了.

但是且慢, 如果你拥有一个独立的客户端, 发送这四种动作是不成问题的, 可是如果你是做 RIA 开发(Flex 或 Silverlight), 目前的浏览器宿主只能支持 GET 和 POST. 后两种动作怎么办?

注: 虽然 Flex 里的 HTTPService 组件有8种动作, 但并不起作用.

也许你已经见过很多动态网站系统采用的解决办法了, 那就是加 URL 参数.

http://www.example.com/admin.asp?action=newpost&title=abc

这样做的好处是通过直观的参数与服务器进行对话.

当然坏处也不少, 按照 HTTP 协议, GET 动作是不能对服务器有副作用的, 因为 GET 只负责读取, 另外这样的 URL 如果被搜索引擎收录了, 或者被用户加入收藏夹, 虽然不是什么致命的问题, 但终究还是对 HTTP 协议的一种误读.

OK~, 既然浏览器不支持, 提倡 Restful 的框架又普遍不满意这种 URL 参数的工作方式, 那 rails 是如何解决这个问题的呢?

Rails 也没有能力解决浏览器的问题, 她同样需要使用额外的方法来模拟 PUT 和 DELETE 动作, 查看产生的源代码, 你会发现她采用的方法是读取 POST 表单里的 hidden 域 _method

html

<input name="_method" type="hidden" value="put" /> 

采用这种办法对于网页的表单来说或许是合适的, 但对于像我这样使用 Flex 开发 RIA 客户端程序的人来说, 会存在下面的问题:

我读取的文档可能是这样的

xml

<user>     <name>路飞</name>     <age>20</age> </user> 

那么我为什么要转换成类似下面的表单来提交?

user[name]=路飞&user[age]=20

如果可以读取也是 xml, 提交亦是 xml, 生活就简单的多了, 不是么?

提交 xml 就意味着 _method 必须放在别的地方(xml 是不能有两个根元素的), rails 2.2.2 之前的版本(具体到哪一版并不清楚), 服务器是接受 GET 参数的, 也就是说可以写成这样:

/users/1?_method=PUT

_method 虽然有了安身之处, 但是且慢! 这样安全吗? 正规吗? 我想 rails 的开发者也对这个东西看不顺眼, 所以在 rails 2.3.2 里, 这种方法被禁止了.

详见: lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb

新版本只在 POST 表单里读取 _method, My God…

幸运的是, methodoverride.rb 这个文件的内容为我指明了另一个方向:

ruby

def call(env)   if env["REQUEST_METHOD"] == "POST"     req = Request.new(env)     method = req.POST[METHOD_OVERRIDE_PARAM_KEY] ||       env[HTTP_METHOD_OVERRIDE_HEADER]     method = method.to_s.upcase     if HTTP_METHODS.include?(method)       env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"]       env["REQUEST_METHOD"] = method     end   end end 

这个文件告诉我们, 服务器除了接受 _method 隐藏域之外, 还接受一个叫 “HTTP_X_HTTP_METHOD_OVERRIDE” 的消息头, 太棒了, 让我们迎着光明继续前进 为了能够看到提交的消息头, 我们需要在 application_controller.rb 里添加点代码. (Rails 2.2.2 之前该文件名为 application.rb)

ruby

class ApplicationController < ActionController::Base   before_filter :print_headers   def print_headers     request.headers.each { |k,v| logger.info("#{k} #{v}") }   end end 

现在回到 Flex 我们创建一个客户端试验一下效果.

actionscript

var svc:HTTPService = new HTTPService(); svc.method = "POST"; svc.url = "/users/1"; svc.headers = { HTTP_X_HTTP_METHOD_OVERRIDE:"PUT", Accept:"application/xml" }; svc.request = { user:{ age:30 } }; svc.send(); 

结果有点长, 删减之后你会发现类似下面这样的内容:

Processing UsersController#create to xml (for 127.0.0.1 at 2009-03-22 11:02:04) [POST] SERVER_NAME ... ....... HTTP_HTTP_X_HTTP_METHOD_OVERRIDE PUT .......

呃… 为什么会多出个 HTTP_ 前缀来呢? 这个问题留给你来解答吧, 我也实在是说不清楚.

不过没关系, 问题已经明朗了, 重新设计一下我们的消息头就可以了.

actionscript

// 首先创建服务代理, 这里只是个例子, 实例上你可能更喜欢用 Mxml. var svc:HTTPService = new HTTPService(); // 只能是 POST, 不要被其他那些参数给骗了. svc.method = "POST"; // 朝用户 ID 为 1 的资源发出 PUT 动作 svc.url = "/users/1"; // 既然不知道哪里来了个 HTTP_ 前缀, 那我们就少打5个字母好了. // Accept 消息头可以使我们的 url 不必以 .xml 结尾来说明 format. svc.headers = { X_HTTP_METHOD_OVERRIDE:"PUT", Accept:"application/xml" }; // 请求的内容是你想要更新的字段, 这里视情况而定, 也可以直接写 xml. svc.request = { user:{ age:30 } }; // 发射!!! svc.send(); 

`Processing UsersController#update to xml (for 127.0.0.1 at 2009-03-22 11:05:13 ) [PUT]

Parameters: {"id"=>"1"} 

……. HTTP_X_HTTP_METHOD_OVERRIDE PUT …….

User Load (0.0ms) SELECT * FROM "users" WHERE ("users"."id" = 1) User Update (2.0ms) UPDATE "users" SET "age" = 30, "updated_at" = '2009-03-22 03:05:13' WHERE "id" = 1 

Completed in 164ms (View: 4, DB: 2) | 200 OK [http://192.168.0.1/users/1]`

OK~ 看来 Rails 已经收到我们的信号, 并且正确识别了我们想要的动作 [PUT]. 其他类似的动作可以由我们自由发挥了, 再也不用受 _method 的牵拌.

嗯, 如果你也是一个像我一样的在技术领域无聊的完美主义者, 但愿这个结果能够令你满意.

http://coldtoto.heroku.com/2009/03/22/flex-put-xml-to-rails/
 

转载于:https://www.cnblogs.com/daiye/archive/2011/06/08/2074888.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值