2012-02-07 9 views
21

Sto cercando di ottenere nginx per lavorare con la mia URI di gestione pushState gestita da backbone.js per me in un'app JavaScript.Riscrivere nginx per pushState-URL

In questo momento l'accesso agli URI con un livello, ad es. example.com/users funziona bene, ma non a due livelli o più in profondità URI, come example.com/users/all, che è menzionato nella Backbone documentation:

Ad esempio, se si dispone di un percorso di/documenti/100, il server web must essere in grado di servire quella pagina, se il browser visita questo URL direttamente

Quindi, essendo lontano dal conoscere le opzioni di riscrittura di nginx, io sono ancora sicuro che posso fare qualcosa di simile rewrite^/index.html; per reindirizzare tutto al mio index.html , ma loosi ng su eventuali file statici (immagini, javascript & css) memorizzati sullo stesso server di cui ho bisogno per poter accedere.

Quindi cosa devo fare invece con la configurazione mostrata di seguito, per fare in modo che funzioni?

server { 
    listen 80; 
    server_name example.com; 

    location/{ 
     root /var/www/example.com; 
     try_files $uri /index.html; 
    } 

} 

risposta

19

Ecco cosa ho fatto alla mia applicazione. Ogni itinerario termina con un '/' (tranne la radice è di per sé) servirà index.html:

location ~ ^/.+/$ { 
    rewrite .* /index.html last; 
    } 

È anche possibile anteporre il percorso:

Backbone.history.start({pushState: true, root: "/prefix/"}) 

e poi:

location ~ ^/prefix/ { 
    rewrite .* /index.html last; 
    } 

O definire una regola per ogni caso.

+3

Il tuo primo suggerimento sembra richiedere una barra finale ... la riscrittura funziona quando vado a "/ ricerca /", ma non "/ search" – andrhamm

+1

come lo risolveresti se non avessi la barra finale? –

+0

Forse una regexp che accetta qualsiasi cosa tranne index.html? –

14

sono riuscito in questo modo:

#set root and index 
root /var/www/conferences/video/; 
index index.html; 

#route all requests that don't serve a file through index.html 
location/{ 
    if (!-e $request_filename){ 
     rewrite ^(.*)$ /index.html break; 
    } 
} 
+1

Ho ottenuto 500 usando questo. –

+0

questa configurazione funziona per me! – llazzaro

30

ho finito per andare con questa soluzione:

server { 

    listen 80; 
    server_name example.com; 
    root /var/www/example.com; 

    # Any route containing a file extension (e.g. /devicesfile.js) 
    location ~ ^.+\..+$ { 
     try_files $uri =404; 
    } 

    # Any route that doesn't have a file extension (e.g. /devices) 
    location/{ 
     try_files $uri /index.html; 
    } 

} 

In questo modo, almeno io ancora ottenere corretti 404 errori se un file non viene trovato .

+2

Grazie, questo ha funzionato per me. Avere un 404 effettivo è importante: se viene richiesto un file JS che non esiste e viene invece restituito HTML, il browser tenta di analizzarlo come JS e genera tutti i tipi di errori JS. Questo potrebbe rovinare una SPA. – ccnokes

+1

Questo dovrebbe essere più in alto. Semplice, elegante e 404 per i file è davvero importante – Igonato

7

Con percorsi app lato client:

/ 
/foo 
/foo/bar 
/foo/bar/baz 
/foo/bar/baz/123 
/tacos 
/tacos/123 

Usa:

server { 
    listen 80; 
    server_name example.com; 
    root /var/www/example.com; 

    gzip_static on; 

    location/{ 
     try_files $uri $uri/ /index.html; 
    } 

    # Attempt to load static files, if not found route to @rootfiles 
    location ~ (.+)\.(html|json|txt|js|css|jpg|jpeg|gif|png|svg|ico|eot|otf|woff|woff2|ttf)$ { 
     try_files $uri @rootfiles; 
    } 

    # Check for app route "directories" in the request uri and strip "directories" 
    # from request, loading paths relative to root. 
    location @rootfiles { 
     rewrite ^/(?:foo/bar/baz|foo/bar|foo|tacos)/(.*) /$1 redirect; 
    } 
} 

Mentre @Adam-Waite's answer lavori per la radice e percorsi a livello di radice, utilizzando se nel contesto luogo è considerato un antipattern , spesso visto durante la conversione di direttive in stile Apache. Vedi: http://wiki.nginx.org/IfIsEvil.

Le altre risposte non coprono percorsi con profondità di directory per il mio caso di utilizzo in un'app di React simile utilizzando react-router e HTML5 pushState abilitati. Quando un percorso viene caricato o aggiornato in una "directory" come example.com/foo/bar/baz/213123, il mio file index.html farà riferimento al file js in un percorso relativo e verrà risolto in example.com/foo/bar/baz/js/app.js anziché in example.com/js/app.js.

Per i casi con la profondità di directory oltre il primo livello, come /foo/bar/baz, nota l'ordine delle directory dichiarati nella direttiva @rootfiles: i percorsi più lunghi possibili bisogno di andare per primo, seguito dal successivo percorso meno profonda /foo/bar e infine /foo.

0

Poiché non vi può essere ajax richiesta API, le seguenti vestiti per questo caso,

server { 
    listen 80; 
    server_name example.com; 
    root /var/www/example.com; 

    # Any route containing a file extension (e.g. /devicesfile.js) 
    location ~ ^.+\..+$ { 
     try_files $uri =404; 
    } 

    # Any route that doesn't have a file extension (e.g. /devices) 
    location/{ 
     try_files $uri /index.html; 
    } 

    # The location block above provides the shortest prefix, of length one, 
    # and so only if all other location blocks fail to provide a match, 
    # this block will be used. 

    # Ajax api starts with /v1/ will be proxied 
    location /v1/ { 
     proxy_pass http://proxy; 
    } 
}