加载资源失败: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 文件。

&lt;script type="text/javascript" src="@Url.Content("~/signalr/hubs")"&gt;&lt;/script&gt;

在 ASP.NET MVC 4 中,您可以执行以下操作:

&lt;script type="text/javascript" src="~/signalr/hubs"&gt;&lt;/script&gt;

见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(未找到)的主要内容,如果未能解决你的问题,请参考以下文章

win10运行中出现duilib加载资源失败。怎么解决

win10运行中出现duilib加载资源失败,又没啥影响,是啥原因啊~~

电脑开机出现duilib加载资源文件失败怎么解决

文档中的最后一张图片加载失败 - “加载资源失败”

散景内联嵌入,“加载资源失败”

Sprite Kit 中的 AVAudioPlayer“加载资源失败”原因资源“无法加载 sound.caf”