Hprose-ruby與Rails結合使用心得

weixin_34124651發表於2017-12-31

Hprose是一個不錯在RPC協議引擎,開源、簡潔、高效、易用,支援多種語言。下面是選取Hprose-ruby與Rails專案結合的一個測試,使用了Rails的middleware方式實現。

  1. 首先使用rails new hprose-rails新建一個專案;
  2. 編輯Gemfile檔案加入uuidtools、hprose兩個gem,需要跨域的同學建議使用rack-cors;
gem 'sqlite3'
gem 'uuidtools'
gem 'hprose'
gem 'rack-cors', :require => 'rack/cors'
  1. 在app目錄下建立一個新的middleware目錄,在該目錄下建立一個data_port.rb檔案;
#encoding: UTF-8
def hello(name)
  'Hello '+name+'!'
end

def get_user(id)
  User.find(id).as_json
end

def get_users_json
  User.all.as_json
end

class DataPort
  def initialize(app)
    @app = app
  end
  def call(env)
    if env['PATH_INFO'] == '/data_port/index'
      hprose_server = HproseHttpService.new
      # hprose_server.crossdomain = true
      hprose_server.add('hello')
      hprose_server.add('get_user')
      hprose_server.add('get_users_json')
      hprose_server.call(env)
    else
      @app.call(env)
    end
  end
end
  1. 編輯config/application.rb,加入以下程式碼,如果跨越使用rack-cors的同學,記得在resource中加入:credentials => true,並同時指定可以跨域的origins域名(不建議使用*萬用字元,有安全問題,詳情請參考rack-cors的說明);
  #rails 5
  config.middleware.insert_before 0, Rack::Cors do
    allow do
      origins 'http://your.permitted.site'
      resource '/data_port/index', :headers => :any, :methods => [:get, :post, :options], :credentials => true
    end
  end

  config.middleware.use DataPort

  #rails3/4
  config.middleware.insert_before 0, 'Rack::Cors' do
    allow do
      origins 'http://your.permitted.site'
      resource '/data_port/index', :headers => :any, :methods => [:get, :post, :options], :credentials => true
    end
  end

  config.middleware.use 'DataPort'
  1. 為了測試資料,在db/development.sqlite3中建一個users表,並在app/models/中建一個user.rb
class User < ActiveRecord::Base
end
  1. 客戶端我使用的是Delphi(好久沒用,最近又有興趣撿起來了,呵呵)。當然,你也可以用ruby、javascript或其他你熟悉的語音,這個就是hprose多語言支援的優勢。
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, HproseCommon,
  HproseClient, HproseHttpClient, Vcl.Grids;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    StringGrid1: TStringGrid;
    procedure Button1Click(Sender: TObject);
    procedure FormDeactivate(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  {TUser = class
    Id: Integer;
    Name: String;
  end;}

var
  Form1: TForm1;
  Client: THproseHttpClient;

implementation

{$R *.dfm}

uses System.json;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Client := THproseHttpClient.Create(nil);
  Client.URI := 'http://localhost:3000/data_port/index';
  //Client.URI := 'http://hprose.com/example/'
end;

procedure TForm1.FormDeactivate(Sender: TObject);
begin
  Client.FreeOnRelease;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    ShowMessage(VarToStr(Client.Invoke('hello', ['中文'])));
  except
    on E:Exception do
      ShowMessage(E.ClassName+': '+E.Message);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  InvokeResult: Variant;
  users: IList;
  user: IMap;
  I: Integer;
  J: Integer;
begin
  try
    InvokeResult:=Client.Invoke('get_users_json');
    if VarIsList(InvokeResult) then
      begin
        ShowMessage('Invoke result is a IMapList.');
        users := VarToList(InvokeResult);
        StringGrid1.RowCount := users.Count+1;
        for I := 0 to users.Count-1 do begin
          user := VarToMap(users.Item[I]);
          for J := 0 to user.Keys.Count-1 do begin
            if I=0 then begin
              StringGrid1.ColCount := user.Keys.Count;
              StringGrid1.Rows[I][J] := user.Keys[J];
            end;
            StringGrid1.Rows[I+1][J] := user.Value[user.Keys[J]];
          end;
        end;
      end
    else
      ShowMessage('Invoke result is *NOT* a IMapList.');
  except
    on E:Exception do
      ShowMessage(E.ClassName+': '+E.Message);
  end;
end;

end.

相關文章