Réécrire nginx pour pushState-URL

J'essaie de faire fonctionner nginx avec ma gestion URI basée sur pushState que backbone.js gère pour moi dans une application Javascript.

En ce moment, accéder aux URI avec un niveau, par exemple. example.com/users fonctionne bien, mais pas les URI à deux niveaux ou plus profonds, tels que example.com/users/all, qui est mentionné dans la documentation Backbone :

Par exemple, si vous avez un itinéraire de /documents/100, votre serveur web doit être en mesure de servir cette page, si le navigateur visite cette URL directement

Donc, étant loin de connaître les options de réécriture de nginx, je suis toujours sûr que je peux faire quelque chose comme rewrite ^ /index.html; pour tout rediriger vers mon index.html, mais perdre sur tous les fichiers statiques éventuels (images, javascript et css) stockés sur le même serveur auquel je dois pouvoir accéder.

Alors, Que dois-je faire à la place avec la configuration actuelle ci-dessous, pour que cela fonctionne?

server {
    listen   80;
    server_name  example.com;

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

}
21
demandé sur Industrial 2012-02-08 02:26:18

5 réponses

Voici ce que j'ai fait à ma demande. Chaque route se terminant par un ' / '(sauf la racine elle-même) servira index.html:

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

Vous pouvez également préfixer votre itinéraire:

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

Puis :

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

, Ou définir une règle pour chaque cas.

19
répondu jney 2012-02-08 13:22:54

J'ai fini par aller avec cette solution:

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 cette façon, au moins je reçois toujours des erreurs 404 appropriées si un fichier n'est pas trouvé.

32
répondu ChrisC 2015-03-05 19:49:48

Je l'ai géré comme ceci:

#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;
   }
}
15
répondu Adam Waite 2013-08-06 09:54:26

Avec les chemins d'application côté client:

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

Utilisation:

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

Alors que la réponse de @ Adam-Waite Fonctionne pour la racine et les chemins au niveau racine, l'utilisation de if dans le contexte d'emplacement est considérée comme un antipattern, souvent vu lors de la conversion des directives de style Apache. Voir: http://wiki.nginx.org/IfIsEvil .

Les autres réponses ne couvrent pas les routes avec une profondeur de répertoire pour mon cas d'utilisation dans une application React similaire utilisant react-router et HTML5 pushState activé. Lorsqu'un la route est chargée ou actualisée dans un" répertoire " tel que example.com/foo/bar/baz/213123 mon index.le fichier html référencera le fichier js à un chemin relatif et résoudra à example.com/foo/bar/baz/js/app.js au lieu de example.com/js/app.js.

Pour les cas avec une profondeur de répertoire au-delà du premier niveau tels que /foo/bar/baz, Notez l'ordre des répertoires déclarés dans la directive @rootfiles: les chemins Les plus longs possibles doivent aller en premier, suivis du chemin suivant {[6] } et enfin /foo.

7
répondu pxwise 2017-05-23 12:02:51

Comme il peut y avoir une api de requête ajax, les combinaisons suivantes pour ce cas,

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;
    }
}
0
répondu Arthur Xu 2016-05-04 15:06:02