2012-02-07 15 views
21

Estoy tratando de obtener nginx para trabajar con mi pushState-URI basado en el manejo que backbone.js administra para mí en una aplicación de Javascript.Reescribiendo nginx para pushState-URL's

Ahora accediendo a URI con un nivel, por ej. example.com/users funciona bien, pero no de dos niveles o más profundo URI, como example.com/users/all, que se menciona en el Backbone documentation:

Por ejemplo, si tiene una ruta de/documentos/100, el servidor web obligada ser capaz de servir a esa página, si el navegador visita a esa URL directamente

Por lo tanto, estar lejos de familiarizarse con las opciones de reescritura de nginx, todavía estoy seguro de que puedo hacer algo como rewrite^/index.html; para redirigir todo a mi index.html , pero loosi ng out en cualquier archivo estático eventual (imágenes, javascript & css) almacenado en el mismo servidor al que necesito poder acceder.

Entonces, ¿qué debo hacer con la configuración actual que se muestra a continuación para que funcione?

server { 
    listen 80; 
    server_name example.com; 

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

} 

Respuesta

19

Esto es lo que hice con mi aplicación. Cada ruta que termina con un '/' (excepto el árbitro raíz auto) servirá index.html:

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

También puede prefijar la ruta:

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

y luego:

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

O define una regla para cada caso.

+3

Su primera sugerencia parece requerir una barra al final ... la reescritura funciona cuando voy a "/ Búsqueda /", pero no "/ search" – andrhamm

+1

¿cómo lo resolvería si no tuviera la barra al final? –

+0

¿Quizás una expresión regular que acepta cualquier cosa menos index.html? –

14

he conseguido de esta manera:

#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

Tengo 500 usando esto. –

+0

¡esta configuración funciona para mí! – llazzaro

30

Terminé yendo con esta solución:

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; 
    } 

} 

De esta manera, al menos yo aún así obtener 404 errores adecuados si no se encuentra un archivo .

+2

Gracias, esto funcionó para mí. Tener un 404 real es importante: si se solicita un archivo JS que no existe y se devuelve HTML en su lugar, el navegador intenta analizarlo como JS y arroja todo tipo de errores JS. Eso podría arruinar un SPA. – ccnokes

+1

Esto debería ser más arriba. Simple, elegante y 404 para archivos es realmente importante – Igonato

7

Con caminos de aplicaciones del lado del cliente:

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

Uso:

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; 
    } 
} 

Mientras @Adam-Waite's answer obras para la raíz y caminos en el nivel raíz, utilizando si es dentro del contexto lugar se considera un antipatrón , a menudo visto al convertir directivas de estilo Apache. Ver: http://wiki.nginx.org/IfIsEvil.

Las otras respuestas no cubren rutas con profundidad de directorio para mi caso de uso en una aplicación React similar que utiliza react-router y HTML5 pushState habilitado. Cuando se carga o actualiza una ruta dentro de un "directorio" como example.com/foo/bar/baz/213123, mi archivo index.html hará referencia al archivo js en una ruta relativa y se resolverá en example.com/foo/bar/baz/js/app.js en lugar de example.com/js/app.js.

Para los casos con la profundidad directorio más allá del primer nivel, tales como /foo/bar/baz, tenga en cuenta el orden de los directorios declarados en la directiva @rootfiles: los caminos más largos posibles tienen que ir primero, seguido por el siguiente camino más superficial /foo/bar y finalmente /foo.

0

Dado que puede haber API petición Ajax, los siguientes trajes para este 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; 
    } 
}