最近想弄个能访问 Internet 的 Android 应用,由于求快因此用了 Ruby on Rails 来提供 HTTP 资源。这方面的资料仍是比较少的,因此把尝试的过程记录下来。html
rails new Test
cd Test
rails generate scaffold product reference:string quantity:decimal
rake db:migrate
启动服务android
rails server
打开http://localhost:3000/productsjson
应该能够看到如下信息(这个就是GET的结果啦,只不过如今尚未记录):ruby
在网页上添加一条记录,单击“New Product”,会转到“http://localhost:3000/products/new”,在里面填写信息后单击“Greate Product”(这样就提交了一个 POST):网络
也就是说,网页端的 GET 和 POST 都是能够执行的。app
打开:http://localhost:3000/products/1.jsonide
能够看到,使用 ruby on rails 是能够直接得到 Json 数据的,这是为何呢?工具
为了弄清楚 Json 数据是怎么来的,先查看 routes测试
rake routes
显示出如下结果:url
因此输入的 http://localhost:3000/products/1.json 对应的是 Controller 里面的 show,在代码里找到show(Test/app/controllers/products_controller.rb):
咦!什么状况?啥都不写就能直接支持 Json ?这也太牛逼了吧。
前面已经知道,用网页能够提交一个 POST,先跟踪一下下这个 POST,用开发者工具查看网络知道页面提交的时候提交了一个 POST:
这个 POST 根据前面的 Routes 应该是给了 controller 里的 create。
因此是 @product = Product.new(product_params) 建立对象,@product.save 保存对象。。那么 product_params 怎么来的呢?
好吧,是这样来的。。。
嗯。。仍是没有解决我想要的 Json 传输方法,后来仍是搜索找大神。。。
在 Test/app/controllers/products_controller.rb 中添加如下代码,用于接受 Android App 提交的 Json 数据。
def create_from_app data_json=JSON.parse request.body.read @product = Product.new(data_json) @product.save end
测试使用的是火狐的 Poster 工具。
测试 GET
测试 POST
补上一段小插曲:直接提交 POST 时是出错的:
把出错的内容粘贴出来存成html,发现是这个错误:
百度求大神,获得这样的答案:
这是从rails 2.0 开始包含的一个新功能,目的在于防止CSRF(Cross-Site Request Forgery)攻击
请原谅我直接暴力地选择了禁用 CSRF 的方式,找到Test/app/controllers/products_controller.rb,插入代码
protect_from_forgery :except => :index # you can disable csrf protection on controller-by-controller basis: skip_before_filter :verify_authenticity_token
重启 rails server
问题解决,再次提交 POST:
也就是说 Android 客户端只要能按照以上格式发送 HTTP 请求就能够了。
在 AndroidManifest.xml 文件中添加如下行
<uses-permission android:name="android.permission.INTERNET"/>
try { final String url = "http://192.168.0.138:3000/products/" + message + ".json"; Thread thread = new Thread(new Runnable() { @Override public void run() { try { HttpGet httpGet = new HttpGet(url); HttpResponse httpResponse = new DefaultHttpClient() .execute(httpGet); if (httpResponse.getStatusLine().getStatusCode() == 200) { result = EntityUtils.toString(httpResponse .getEntity()); } } catch (Exception e) { e.printStackTrace(); } } }); thread.start(); thread.join(); } catch (InterruptedException e) { e.printStackTrace(); }
try{ Thread threadPost = new Thread(new Runnable() { @Override public void run() { try { final String url = "http://192.168.0.138:3000/products"; HttpPost httpPost = new HttpPost(url); JSONObject json = new JSONObject(); json.accumulate("reference", "888"); json.accumulate("quantity", "8"); JSONObject response = null; StringEntity s = new StringEntity(json.toString()); s.setContentEncoding("UTF-8"); s.setContentType("application/json"); httpPost.setEntity(s); HttpResponse httpResponse = new DefaultHttpClient() .execute(httpPost); if (httpResponse.getStatusLine().getStatusCode() == 200) { result = EntityUtils.toString(httpResponse.getEntity()); } } catch (Exception e) { e.printStackTrace(); } } }); threadPost.start(); threadPost.join(); } catch (Exception e) { e.printStackTrace(); }