我整天都被困在这一天。我有David Heinemeier Hansson非常简单的ActionCable示例应用程序(聊天应用程序)正常工作(https://www.youtube.com/watch?v=n0WUjGkDFS0)。
我正试图用iPhone应用程序点击websocket连接。当我连接到ws://localhost:3000/cable
时,我能够收到ping,但我不太确定如何从javascript环境之外订阅频道。
答案 0 :(得分:11)
哦,伙计,我在阅读完这个问题后也遇到了这个问题。
过了一会儿,我终于找到了这个神奇的Github问题页面:
https://github.com/rails/rails/issues/22675
我明白这个补丁会破坏一些测试。那不是 我很惊讶。但我认为最初的问题仍然具有现实意义 并且不应该被关闭。
发送到服务器的以下JSON应该会成功:
{"命令":"订阅","标识符":{"频道":" ChangesChannel"} }
没有!相反,你必须发送:
{"命令&#34 ;: "订阅""标识符":" {\"信道\":\" ChangesChannel \"}&#34 ;}
我终于得到了iOS应用程序,根据Github用户对Rails问题的建议订阅了房间频道。
我的设置如下:
我假设您知道如何使用Cocoapods来安装PocketSocket。
相关代码如下:
#import <PocketSocket/PSWebSocket.h>
@interface ViewController : UIViewController <PSWebSocketDelegate, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate>
@property (nonatomic, strong) PSWebSocket *socket;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self initViews];
[self initConstraints];
[self initSocket];
}
-(void)initSocket
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"ws://localhost:3000/cable"]];
self.socket = [PSWebSocket clientSocketWithRequest:request];
self.socket.delegate = self;
[self.socket open];
}
-(void)joinChannel:(NSString *)channelName
{
NSString *strChannel = @"{ \"channel\": \"RoomChannel\" }";
id data = @{
@"command": @"subscribe",
@"identifier": strChannel
};
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:nil];
NSString * myString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"myString= %@", myString);
[self.socket send:myString];
}
#pragma mark - PSWebSocketDelegate Methods -
-(void)webSocketDidOpen:(PSWebSocket *)webSocket
{
NSLog(@"The websocket handshake completed and is now open!");
[self joinChannel:@"RoomChannel"];
}
-(void)webSocket:(PSWebSocket *)webSocket didReceiveMessage:(id)message
{
NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSString *messageType = json[@"type"];
if(![messageType isEqualToString:@"ping"] && ![messageType isEqualToString:@"welcome"])
{
NSLog(@"The websocket received a message: %@", json[@"message"]);
[self.messages addObject:json[@"message"]];
[self.tableView reloadData];
}
}
-(void)webSocket:(PSWebSocket *)webSocket didFailWithError:(NSError *)error
{
NSLog(@"The websocket handshake/connection failed with an error: %@", error);
}
-(void)webSocket:(PSWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
{
NSLog(@"The websocket closed with code: %@, reason: %@, wasClean: %@", @(code), reason, (wasClean) ? @"YES": @"NO");
}
我还在订阅类源代码中挖掘了一些内容:
def add(data)
id_key = data['identifier']
id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access
subscription_klass = connection.server.channel_classes[id_options[:channel]]
if subscription_klass
subscriptions[id_key] ||= subscription_klass.new(connection, id_key, id_options)
else
logger.error "Subscription class not found (#{data.inspect})"
end
end
注意这一行:
connection.server.channel_classes[id_options[:channel]]
我们需要使用该类的名称作为频道。
DHH youtube视频使用&#34; room_channel&#34;对于房间名称,但该频道的类文件名为&#34; RoomChannel&#34;。
我们需要使用类名而不是通道的实例名。
以防其他人想知道如何发送消息,这是我的iOS代码向服务器发送消息:
-(void)sendMessage:(NSString *)message
{
NSString *strMessage = [[NSString alloc] initWithFormat:@"{ \"action\": \"speak\", \"message\": \"%@\" }", message];
NSString *strChannel = @"{ \"channel\": \"RoomChannel\" }";
id data = @{
@"command": @"message",
@"identifier": strChannel,
@"data": strMessage
};
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:nil];
NSString * myString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"myString= %@", myString);
[self.socket send:myString];
}
这假设您已连接UITextField以处理按回车键或某些&#34;发送&#34;按钮上的某个按钮。
这个整个演示应用程序是一个快速的黑客,显然,如果我要在一个真正的应用程序中进行,我会使我的代码更清洁,更可重用并将它抽象成一个类。
为了让iPhone应用程序在真实设备上与Rails服务器通信,而不是iPhone模拟器。
执行以下操作:
修改您的Rail config > environment > development.rb
文件,并在end
关键字之前的某处放置以下行:
Rails.application.config.action_cable.allowed_request_origins = ['http://10.1.1.10:3000']
使用以下命令启动Rails服务器:
rails server -b 0.0.0.0
在iPhone设备上构建并运行您的iPhone应用程序。您现在应该能够连接并发送消息:D
我从以下链接获得了这些解决方案:
Request origin not allowed: http://localhost:3001 when using Rails5 and ActionCable
Rails 4.2 server; private and public ip not working
希望将来帮助他人。
答案 1 :(得分:4)
//首先打开套接字连接
var ws = new WebSocket("ws://localhost:3000/cable");
//订阅频道
//&#39;我&#39;应该在json
var i = { 'command': 'subscribe', 'identifier': {'channel':'ProfileChannel', 'Param_1': 'Value_1',...}};
ws.send(i);
//之后,您将在&#39; onmessage&#39;内收到数据。功能
干杯!
答案 2 :(得分:0)
实际上,以下是我用来连接动作电缆的代码段。
function WebSocketTest()
{
var ws = new WebSocket("ws://localhost:3000/cable");
ws.onopen = function(data)
{
var i = JSON.stringify({"command":"subscribe" , "identifier": JSON.stringify({"channel":"CHANNEL_NAME"})});
// send data request
var j = JSON.stringify({"command":"message","identifier": JSON.stringify({"channel":"CHANNEL_NAME"}),"data": {"message":"Hello World","action": "METHOD_NAME_IN_CHANNEL","email": "abc@xyz.com", "token" : "xxxxxxxxxxxxx", "id": {"id_message" : "something", "ddd" : "something"}}})
var response = ws.send(i);
setTimeout(function()
{
var response1 = ws.send(j);
}, 1000);
};
ws.onmessage = function (evt)
{
var received_msg = evt.data;
};
}