Backbone Routes Not Being Called

2019-04-21 08:00发布

问题:

I have a strange issue I haven't been able to figure out as of yet. It's very simple which is probably why I'm having trouble with it :)

First, here's the routing table...

routes: {
    '': 'root', //called
    'report': 'report', // called
    'report/add': 'reportAdd', // not called
    'report/print': 'reportPrint', // not called
    'report/settings': 'reportSettings', // not called
},

You'll see I marked which ones are working and which ones aren't. The problem boils down to all subroutes (i.e report/add) not being matched.

Backbone history is called properly in main.js like so:

app.Router = new Router();
Backbone.history.start({ pushState: true });

Obviously, that's in the right spot because routes are working just not sub-routes. I've tried the root options of Backbone.history and the silent parameter all without any luck.

I imagine it's a configuration/setup issue but I haven't been able to find any answers. What am I doing wrong? Any help is much appreciated.

Btw, I'm using requirejs and Backbone Boilerplate but I don't see how that would make a difference.

UPDATE: Although the answer provided is technically correct, the problem is with Backbone Boilerplate. See the bottom of this blog post for an explanation. I'm having the same issue as the first commenter there.

回答1:

As discussed in the comments, the problem is that, when using push-state style URLs, the server doesn't recognize the Backbone route URLs.

For illustration, say your application's root is at server/app/index.html, and you're trying to use a URL that Backbone routes to /report/print. With URL fragment routing, this is fine:

http://server/app/index.html#report/print

The server ignores the part after # and returns index.html; then on load Backbone routes to report/print.

But if you're using push-state routing, then the URL looks like this:

http://server/app/index.html/report/print

And the server throws a 404 error because it doesn't recognize anything at that path, so Backbone is never even loaded.


The solution is to either:

  1. As the Backbone.js docs note, modify server code, so that the server renders the correct content for each Backbone route, or
  2. (which I think is easier) put a URL rewrite in place on the web server (IIS, Apache), so that it will return index.html for any request that is a Backbone route like index.html/report/print, index.html/report/add, etc.

In IIS, for example, you'd put the following in the web.config under your application root:

<rewriteMaps>
    <rewriteMap name="StaticRewrites">
        <add key="index.html/report/print" value="index.html" />
        <add key="index.html/report/add" value="index.html" />
        <!-- etc -->
    </rewriteMap>
</rewriteMaps>