Skip to content

URL friendly, riscrittura URL e reverse proxy

Questo documento spiega come integrare Mindtraining Platform con URL friendly e come configurare la riscrittura degli URL o un reverse proxy affinché navigazione diretta, preferiti e refresh funzionino correttamente.


Indice


Il problema

Mindtraining Platform usa il routing lato client: il browser carica un singolo index.html (o equivalente) e JavaScript aggiorna la vista in base al path dell'URL. Quando un utente:

  • Naviga direttamente a https://yoursite.com/games/crossword/archive

  • Salva nei preferiti un deep link

  • Aggiorna la pagina su una route diversa dalla root

…il browser invia una richiesta al server per quel path esatto. Senza configurazione, il server cerca un file in /games/crossword/archive e restituisce 404, perché quel path esiste solo nel router della SPA, non su disco.


La soluzione

Tutte le richieste verso route SPA devono servire lo stesso file di ingresso (index.html o script.js). La SPA poi legge l'URL e renderizza la vista corretta. Questo si ottiene tramite:

  1. URL rewrite — mappare internamente tutte le route SPA al file di ingresso

  2. Reverse proxy — inoltrare le richieste a un backend che serve la SPA

  3. Fallback / catch-all — trattare ogni path non statico come route SPA


Apache

Usando .htaccess (mod_rewrite)

Inserisci questo nel document root o nel sottodirectory della SPA (ad esempio /games/.htaccess):

apache
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /games/

  # Non riscrivere file o directory esistenti
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d

  # Riscrivi tutto il resto verso index.html
  RewriteRule ^ index.html [L]
</IfModule>

Note:

  • Sostituisci /games/ con il tuo base path SPA. Usa / se la SPA è in root.

  • Assicurati che mod_rewrite sia abilitato: a2enmod rewrite (Debian/Ubuntu).

  • AllowOverride All deve essere impostato affinché .htaccess venga rispettato.

Usando VirtualHost (senza .htaccess)

apache
<VirtualHost *:80>
  ServerName yoursite.com
  DocumentRoot /var/www/mindtraining

  <Directory /var/www/mindtraining>
    Options -Indexes +FollowSymLinks
    AllowOverride None
    Require all granted

    RewriteEngine On
    RewriteBase /games/
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^ index.html [L]
  </Directory>
</VirtualHost>

SPA in una sottodirectory (ad esempio /games)

Se la SPA vive sotto /games e il tuo entrypoint è index.html in quella cartella:

apache
<Directory /var/www/html/games>
  RewriteEngine On
  RewriteBase /games/
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^ /games/index.html [L]
</Directory>

Nginx

Fallback SPA di base

nginx
server {
  listen 80;
  server_name yoursite.com;
  root /var/www/mindtraining;

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

SPA in una sottodirectory (ad esempio /games)

nginx
server {
  listen 80;
  server_name yoursite.com;
  root /var/www/html;

  location /games {
    alias /var/www/html/games;
    try_files $uri $uri/ /games/index.html;
  }
}

Con reverse proxy verso un'origine statica/CDN

Se la SPA è servita da un CDN o da un'altra origin:

nginx
server {
  listen 80;
  server_name yoursite.com;

  location / {
    proxy_pass <https://cdn.example.com/mindtraining/>;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # Fallback SPA: se l'upstream risponde 404, servi index
    proxy_intercept_errors on;
    error_page 404 = /index.html;
  }
}

Subpath + proxy più robusto

nginx
server {
  listen 80;
  server_name yoursite.com;

  location /games/ {
    proxy_pass <https://cdn.example.com/mindtraining/>;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # Non riscrivere gli asset statici
    proxy_intercept_errors on;
    proxy_next_upstream error timeout http_404;
    error_page 404 = @spa_fallback;
  }

  location @spa_fallback {
    rewrite ^ /games/index.html break;
    proxy_pass <https://cdn.example.com/mindtraining/>;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
  }
}

Alternative (senza Apache/Nginx)

Se non puoi usare Apache o Nginx (ad esempio serverless, PaaS o un semplice server Node), usa uno di questi approcci.

1. Node.js (Express)

js
const express = require('express')
const path = require('path')

const app = express()
const PORT = process.env.PORT || 3000

// Servi file statici (JS, CSS, immagini)
app.use(express.static(path.join(__dirname, 'dist')))

// Fallback SPA: tutte le altre route servono index.html
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist', 'index.html'))
})

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})

SPA in sottodirectory (ad esempio /games):

js
const express = require('express')
const path = require('path')

const app = express()
const BASE = '/games'

app.use(BASE, express.static(path.join(__dirname, 'dist')))

app.get(`${BASE}/*`, (req, res) => {
  res.sendFile(path.join(__dirname, 'dist', 'index.html'))
})

app.listen(process.env.PORT || 3000)

2. Vercel (vercel.json)

json
{
  "rewrites": [
    { "source": "/(.*)", "destination": "/index.html" }
  ]
}

Per un subpath:

json
{
  "rewrites": [
    { "source": "/games/:path*", "destination": "/games/index.html" }
  ]
}

3. Netlify (_redirects o netlify.toml)

_redirects (in public/ o nella root del progetto):

txt
/*    /index.html   200

netlify.toml:

toml
[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

Per il subpath /games:

txt
/games/*    /games/index.html    200

4. AWS S3 + CloudFront (hosting statico)

S3 non supporta rewrite. Usa CloudFront Functions o Lambda@Edge:

CloudFront Function (viewer request o origin request):

js
function handler(event) {
  var request = event.request
  var uri = request.uri

  // Non riscrivere se sembra un file
  if (uri.includes('.') && !uri.endsWith('.html')) {
    return request
  }

  // Fallback SPA
  if (!uri.endsWith('/') && !uri.includes('.')) {
    request.uri = '/index.html'
  } else if (uri.endsWith('/')) {
    request.uri = uri + 'index.html'
  }

  return request
}

5. Firebase Hosting (firebase.json)

json
{
  "hosting": {
    "public": "dist",
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

6. GitHub Pages

GitHub Pages non supporta rewrite lato server. Opzioni:

  • Usa il trucco di 404.html: crea una pagina 404 personalizzata che carichi la SPA e faccia redirect lato client. Non è ideale per SEO o deep link.

  • Usa un hash router lato client (#/games/crossword) invece del routing basato sul path. Non richiede configurazione server, ma gli URL sono meno puliti.

  • Ospita la SPA altrove (Vercel, Netlify, ecc.) e punta lì il tuo dominio.


Specifiche di Mindtraining Platform

Questa piattaforma usa TanStack Router con un basepath dinamico proveniente dall'API. Route tipiche:

Pattern di pathEsempio
Home/ o /{basepath}/
Gioco di oggi/{basepath}/crossword/
Archivio/{basepath}/crossword/archive
Statistiche/{basepath}/crossword/statistics
Data specifica/{basepath}/crossword/2024-03-18

Il basepath viene configurato per sito/dominio. Assicurati che le tue regole coprano tutto il basepath. Per esempio, se basepath è /games:

  • Apache: RewriteBase /games/ e servire index.html per tutte le richieste non-file sotto /games

  • Nginx: location /games { try_files $uri $uri/ /games/index.html; }

  • Express: montare statici + fallback sotto /games


Client integration documentation maintained in-repo.