此錯誤的原因可能是您訂閱的標識符和消息傳遞的區別。我用ActionCable在導軌5 API模式(具有寶石 'devise_token_auth')和I面臨同樣的錯誤太:
SUBSCRIBE(ERROR):
{"command":"subscribe","identifier":"{\"channel\":\"UnreadChannel\"}"}
SEND MESSAGE(ERROR):
{"command":"message","identifier":"{\"channel\":\"UnreadChannel\",\"correspondent\":\"[email protected]\"}","data":"{\"action\":\"process_unread_on_server\"}"}
出於某種原因ActionCable需要您的客戶端實例應用相同的標識符兩次 - 在訂購的同時消息:
/var/lib/gems/2.3.0 /gems/actioncable-5.0.1/lib/action_cable/connection/subscriptions.rb:74
def find(data)
if subscription = subscriptions[data['identifier']]
subscription
else
raise "Unable to find subscription with identifier: #{data['identifier']}"
end
end
這是一個活生生的例子:我實現傳輸子系統,用戶在現實得到了未讀郵件通知時間模式。在訂閱的時候,我並不需要correspondent
,但是在消息傳遞的時候 - 我確實需要。
所以解決方案是將correspondent
從標識符散列移動到數據散列:
SEND MESSAGE(CORRECT):
{"command":"message","identifier":"{\"channel\":\"UnreadChannel\"}","data":"{\"correspondent\":\"[email protected]\",\"action\":\"process_unread_on_server\"}"}
這種方式,誤差消失。
這裏是我的UnreadChannel
代碼:
class UnreadChannel < ApplicationCable::Channel
def subscribed
if current_user
unread_chanel_token = signed_token current_user.email
stream_from "unread_#{unread_chanel_token}_channel"
else
# http://api.rubyonrails.org/classes/ActionCable/Channel/Base.html#class-ActionCable::Channel::Base-label-Rejecting+subscription+requests
reject
end
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
def process_unread_on_server param_message
correspondent = param_message["correspondent"]
correspondent_user = User.find_by email: correspondent
if correspondent_user
unread_chanel_token = signed_token correspondent
ActionCable.server.broadcast "unread_#{unread_chanel_token}_channel",
sender_id: current_user.id
end
end
end
幫手:(你不應該讓普通的標識符 - 編碼他們以同樣的方式Rails的編碼普通餅乾簽署的)
def signed_token string1
token = string1
# http://vesavanska.com/2013/signing-and-encrypting-data-with-tools-built-in-to-rails
secret_key_base = Rails.application.secrets.secret_key_base
verifier = ActiveSupport::MessageVerifier.new secret_key_base
signed_token1 = verifier.generate token
pos = signed_token1.index('--') + 2
signed_token1.slice pos..-1
end
要總結一下如果您稍後要調用MESSAGE命令,則必須先調用SUBSCRIBE命令。兩個命令都必須具有相同的標識符散列(此處爲「通道」)。有趣的是,subscribed
鉤子並不是必需的(!) - 即使沒有它,你仍然可以發送消息(在SUBSCRIBE之後)(但沒有人會收到它們 - 沒有subscribed
鉤子)。
另一個有趣這裏的一點是,subscribed
鉤裏面我用這個代碼:
stream_from "unread_#{unread_chanel_token}_channel"
明明unread_chanel_token
可能是什麼 - 它僅適用於「接收」方向。
所以訂閱標識符(如\"channel\":\"UnreadChannel\"
)一直被認爲是一個「密碼」,爲未來消息發送操作(例如,它僅適用於「發送」方向) - 如果你想送一條消息(首先發送訂閱,然後)再次提供相同的「通過」,否則您將得到所描述的錯誤。
而更多的是 - 它實際上只是一個「密碼」 - 正如你所看到的,實際上你可以發送郵件到。無論您想要的:
ActionCable.server.broadcast "unread_#{unread_chanel_token}_channel", sender_id: current_user.id
奇怪的,對不對?
這一切都很複雜。爲什麼在official documentation中沒有描述?
僅供參考,已通過https://github.com/rails/rails/pull/26547修復 –