最近想弄個能訪問 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(); }