加载资源失败:http://website.azurewebsites.net/signalr/hubs 服务器响应状态为 404(未找到)
Posted
技术标签:
【中文标题】加载资源失败:http://website.azurewebsites.net/signalr/hubs 服务器响应状态为 404(未找到)【英文标题】:Failed to load resource: the http://website.azurewebsites.net/signalr/hubs server responded with a status of 404 (Not Found) 【发布时间】:2017-01-04 21:19:02 【问题描述】:我使用 SignalR 技术的 MVC-5 Azure 托管 Web 应用程序(VS 2013 / VB)似乎没有创建必要的 SignalR/hubs javascript 页面。
这里是所有细节:
首先,由于我认为 Azure 不允许创建 /signalr/hubs 源页面,因此我从自己的 SignalR 测试应用中“窃取”了一个示例中心页面。然后,我将 signalr.js 文件添加到我的 Web 应用程序的 Scripts/Custom 文件夹中。这是 JavaScript 文件:
(function ($, window, undefined)
/// <param name="$" type="jQuery" />
"use strict";
if (typeof ($.signalR) !== "function")
throw new Error("SignalR: SignalR is not loaded. Please ensure jquery.signalR-x.js is referenced before ~/signalr/js.");
var signalR = $.signalR;
function makeProxyCallback(hub, callback)
return function ()
// Call the client hub method
callback.apply(hub, $.makeArray(arguments));
;
function registerHubProxies(instance, shouldSubscribe)
var key, hub, memberKey, memberValue, subscriptionMethod;
for (key in instance)
if (instance.hasOwnProperty(key))
hub = instance[key];
if (!(hub.hubName))
// Not a client hub
continue;
if (shouldSubscribe)
// We want to subscribe to the hub events
subscriptionMethod = hub.on;
else
// We want to unsubscribe from the hub events
subscriptionMethod = hub.off;
// Loop through all members on the hub and find client hub functions to subscribe/unsubscribe
for (memberKey in hub.client)
if (hub.client.hasOwnProperty(memberKey))
memberValue = hub.client[memberKey];
if (!$.isFunction(memberValue))
// Not a client hub function
continue;
subscriptionMethod.call(hub, memberKey, makeProxyCallback(hub, memberValue));
$.hubConnection.prototype.createHubProxies = function ()
var proxies = ;
this.starting(function ()
// Register the hub proxies as subscribed
// (instance, shouldSubscribe)
registerHubProxies(proxies, true);
this._registerSubscribedHubs();
).disconnected(function ()
// Unsubscribe all hub proxies when we "disconnect". This is to ensure that we do not re-add functional call backs.
// (instance, shouldSubscribe)
registerHubProxies(proxies, false);
);
proxies['bpHub'] = this.createHubProxy('bpHub');
proxies['bpHub'].client = ;
proxies['bpHub'].server =
begin: function ()
return proxies['bpHub'].invoke.apply(proxies['bpHub'], $.merge(["new"], $.makeArray(arguments)));
,
hello: function ()
return proxies['bpHub'].invoke.apply(proxies['bpHub'], $.merge(["send"], $.makeArray(arguments)));
,
helloServer: function ()
return proxies['bpHub'].invoke.apply(proxies['bpHub'], $.merge(["broadcast"], $.makeArray(arguments)));
;
return proxies;
;
signalR.hub = $.hubConnection("/signalr", useDefaultPath: false );
$.extend(signalR, signalR.hub.createHubProxies());
(window.jQuery, window));
现在,我知道代理映射到我设置的类中的函数。但鉴于我的应用程序非常大,我不太确定该怎么做。本质上,我只是在项目中添加了一些类,因此它们位于根文件夹中。然后在 Startup.vb 文件中,我这样做;
Imports Microsoft.Owin
Imports Owin
Imports Microsoft.AspNet.SignalR
<Assembly: OwinStartup(GetType(Startup))>
Public Class Startup
Public Sub Configuration(app As IAppBuilder)
Dim cn As String = ConfigurationManager.ConnectionStrings("AzureServiceBus").ConnectionString
GlobalHost.DependencyResolver.UseServiceBus(cn, "dtxEarth3")
app.MapSignalR()
End Sub
End Class
然后,根据 Roberto Vespa 的 SignalR Real-Time Application Cookbook 一书,我将以下类添加到我的应用程序的根文件夹中; sigRmb.vb;
Imports System.Collections.Generic
Imports System.Threading.Tasks
Imports Microsoft.AspNet.SignalR
Imports Microsoft.AspNet.SignalR.Client
Imports Microsoft.AspNet.SignalR.Messaging
Imports Microsoft.AspNet.SignalR.Hubs
<HubName("bpHub")>
Public Class SignalRBackplaneMessageBus
Inherits ScaleoutMessageBus
Private ReadOnly _connection As HubConnection
Private ReadOnly _hub As IHubProxy
Public Sub New(dependencyResolver As IDependencyResolver, configuration As SignalRBackplaneConfiguration)
MyBase.New(dependencyResolver, configuration)
_connection = New HubConnection(configuration.EndpointAddress)
_hub = _connection.CreateHubProxy("bpHub")
_hub.[On](Of Byte())("broadcast", Function(m)
Dim message = SignalRBackplaneMessage.FromBytes(m)
OnReceived(0, message.Id, message.ScaleoutMessage)
End Function)
_connection.Start().Wait()
End Sub
Protected Overrides Function Send(streamIndex As Integer, messages As IList(Of Message)) As Task
Return Send(messages)
End Function
Protected Overrides Function Send(messages As IList(Of Message)) As Task
If _connection.State <> ConnectionState.Connected Then
Return Task.FromResult(False)
End If
Dim newId = _hub.Invoke(Of Long)("GetId").Result
Dim data = SignalRBackplaneMessage.ToBytes(newId, messages)
Return _hub.Invoke("Publish", data)
End Function
End Class
sigRconfig;
Imports Microsoft.AspNet.SignalR.Messaging
Public Class SignalRBackplaneConfiguration
Inherits ScaleoutConfiguration
Private m_EndpointAddress As String = "Endpoint=sb://dtxdrill-ns.servicebus.windows.net/;SharedAccessKeyName=RigMon100;SharedAccessKey=U7/6C+1y1kExpCMVgG+1tZpvz6um/d4NOiucComR/CU="
Public Property EndpointAddress() As String
Get
Return m_EndpointAddress
End Get
Set(value As String)
m_EndpointAddress = value
End Set
End Property
End Class
sigRbm;
Imports System.Collections.Generic
Imports System.IO
Imports Microsoft.AspNet.SignalR.Messaging
Public Class SignalRBackplaneMessage
Private m_Id As ULong
Private m_ScaleoutMessage As ScaleoutMessage
Public Property Id() As ULong
Get
Return m_Id
End Get
Private Set(value As ULong)
m_Id = value
End Set
End Property
Public Property ScaleoutMessage() As ScaleoutMessage
Get
Return m_ScaleoutMessage
End Get
Private Set(value As ScaleoutMessage)
m_ScaleoutMessage = value
End Set
End Property
Public Shared Function ToBytes(id As Long, messages As IList(Of Message)) As Byte()
If messages Is Nothing Then
Throw New ArgumentNullException("messages")
End If
Using ms = New MemoryStream()
Dim binaryWriter = New BinaryWriter(ms)
Dim scaleoutMessage = New ScaleoutMessage(messages)
Dim buffer = scaleoutMessage.ToBytes()
binaryWriter.Write(id)
binaryWriter.Write(buffer.Length)
binaryWriter.Write(buffer)
Return ms.ToArray()
End Using
End Function
Public Shared Function FromBytes(data As Byte()) As SignalRBackplaneMessage
Using stream = New MemoryStream(data)
Dim binaryReader = New BinaryReader(stream)
Dim id = CULng(binaryReader.ReadInt64())
Dim count = binaryReader.ReadInt32()
Dim buffer = binaryReader.ReadBytes(count)
Return New SignalRBackplaneMessage() With _
.Id = id, _
.ScaleoutMessage = ScaleoutMessage.FromBytes(buffer) _
End Using
End Function
End Class
还有这个,叫做sigR_DependencyResolverExtensions.vb;
Imports System.Runtime.CompilerServices
Imports Microsoft.AspNet.SignalR
Imports Microsoft.AspNet.SignalR.Messaging
Module sigR_DependencyResolverExtensions
<System.Runtime.CompilerServices.Extension> _
Public Sub UseSignalRBackplane(resolver As IDependencyResolver, endpointAddress As String)
resolver.UseSignalRBackplane(New SignalRBackplaneConfiguration() With _
.EndpointAddress = endpointAddress _
)
End Sub
<System.Runtime.CompilerServices.Extension> _
Public Sub UseSignalRBackplane(resolver As IDependencyResolver, configuration As SignalRBackplaneConfiguration)
resolver.Register(GetType(IMessageBus), Function() New SignalRBackplaneMessageBus(resolver, configuration))
End Sub
End Module
最后,在我看来,我有;
@Code
Layout = Nothing
End Code
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Drillers Readout - HTI Job #@ViewBag.JobNumber</title>
<style>
#messages li
list-style-type: none;
</style>
@Styles.Render("~/Content/css")
@Styles.Render("~/Content/themes/base/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@Scripts.Render("~/bundles/jqueryui")
@Scripts.Render("~/bundles/signalR")
<script src="~/Scripts/jquery.signalR-2.2.1.js"></script>
<script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script>
<script src="~/Scripts/Custom/signalr.js"></script>
<script type="text/javascript">
$(function ()
//var cn = $.hubConnection();
$.connection.hub.url = "@Url.Content("~/Scripts/Custom/signalr.js")";
var hub = $.connection.bpHub;
$.connection.hub.start().done(function()
alert('okay 1');
)
.fail(function(e)
alert('uh-oh! Connection Error ' + e);
);
//var myProxy = cn.createHubProxy('bpHub');
//var backplane = cn.backplane;
//myProxy.on('broadcast', function (message)
// $('#messages').prepend($('<li/>').text(message));
//);
//cn.start().done(function ()
// myProxy.invoke('new');
//)
);
</script>
</head>
<body>
@*<span id="newTime"></span><br />
<input type="button" id="btnClick" value="Send Message" /><br />
<span id="message"></span>*@
<ul id="messages"></ul>
</body>
</html>
但是当我运行它时,我得到(在 Chrome 中); http://mywebsite.azurewebsites.net/Scripts/Custom/signalr.js/negotiate?clientProtocol=1.5&connectionData=... 加载资源失败:服务器响应状态为 404...
我知道我的代码有几个问题,包括设置 signalr.js 文件等等。请帮忙。
【问题讨论】:
【参考方案1】:您的 SignalR 应用程序是否在您的本地环境中工作?或者它只在 Azure 端不起作用?对于一般 404 问题,请在 Global.asax 中标记确保您已调用 MapHubs(),并确保在您的应用程序中的任何其他路由之前注册 Hub 路由。假设您使用的是 ASP.NET MVC3,请使用 @Url.Content 引用 JavaScript 文件。
<script type="text/javascript" src="@Url.Content("~/signalr/hubs")"></script>
在 ASP.NET MVC 4 中,您可以执行以下操作:
<script type="text/javascript" src="~/signalr/hubs"></script>
见SignalR FAQ on GitHub
如果这是 Azure 端的问题,请确保 SignalR 相关文件已通过 KUDU 工具上传到 Azure 端。另外请检查this article是否开启了websocket。
【讨论】:
Websocket 已开启。我只在生产端工作(从不本地),尽管我确实创建了一个 SignalR 应用程序,它在 localhost 上运行一个计时器并且它工作正常。 MapHubs 是 MVC-4 的残余;我相信,在 Startup 的 Configuration Sub 中执行 app.MapSignalR() 就是 MVC-5 所需要的,这就是我正在使用的(见标题)。我创建了自己的 JS 集线器并将其放在 Scripts/custom/signalr.js 中。我正在尝试使用 ScaleoutMessageBus,因为我的数据位于 Azure ServiceBus 队列中,但我无法正常工作。 请看我上面的大量编辑。我认为它包含与信号器和我的问题有关的所有信息。谢谢。以上是关于加载资源失败:http://website.azurewebsites.net/signalr/hubs 服务器响应状态为 404(未找到)的主要内容,如果未能解决你的问题,请参考以下文章