Enhance SEO and URL handling in router and server
- Updated the router to ensure canonical URLs are correctly formatted, particularly for the home path. - Added middleware in the server to remove tracking/session query parameters, preventing duplicate URLs from being indexed by Google. - Set canonical link headers in SEO routes to assist search engines in URL attribution. These changes improve SEO performance and ensure cleaner URL structures across the application.
This commit is contained in:
@@ -243,7 +243,9 @@ function updateJsonLd(schema) {
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
const meta = to.meta || {};
|
||||
const pageUrl = `${SITE_URL}${to.path}`;
|
||||
// Immer eine eindeutige kanonische URL (Home explizit mit / am Ende der Origin)
|
||||
const path = to.path === '' ? '/' : to.path;
|
||||
const pageUrl = path === '/' ? `${SITE_URL}/` : `${SITE_URL}${path}`;
|
||||
const title = meta.title || 'SingleChat';
|
||||
const description = meta.description || '';
|
||||
const keywords = meta.keywords || '';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Server as SocketIOServer } from 'socket.io';
|
||||
import cookieParser from 'cookie-parser';
|
||||
import session from 'express-session';
|
||||
import cors from 'cors';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { fileURLToPath, URL as NodeURL } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import { setupBroadcast } from './broadcast.js';
|
||||
import { setupRoutes } from './routes.js';
|
||||
@@ -117,6 +117,44 @@ if (IS_PRODUCTION) {
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
// Tracking-/Session-Query entfernen (wtd, js=no), damit Google keine Duplikat-URLs indexiert.
|
||||
// Suchkonsole: "Alternative Seite mit richtigem kanonischen Tag" fuer /?wtd=... verschwindet nach Neu-Crawl.
|
||||
app.use((req, res, next) => {
|
||||
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
if (req.path.startsWith('/api')) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
const host = req.get('host') || 'localhost';
|
||||
const proto = req.get('x-forwarded-proto') || req.protocol || 'https';
|
||||
const raw = req.originalUrl.split('#')[0];
|
||||
let u;
|
||||
try {
|
||||
u = new NodeURL(raw, `${proto}://${host}`);
|
||||
} catch {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
const hadWtd = u.searchParams.has('wtd');
|
||||
const hadJsNo = u.searchParams.get('js') === 'no';
|
||||
if (!hadWtd && !hadJsNo) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
if (hadWtd) u.searchParams.delete('wtd');
|
||||
if (hadJsNo) u.searchParams.delete('js');
|
||||
const search = u.searchParams.toString();
|
||||
const dest = u.pathname + (search ? `?${search}` : '');
|
||||
if (dest !== raw) {
|
||||
res.redirect(301, dest);
|
||||
return;
|
||||
}
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
// Statische Dateien aus docroot
|
||||
@@ -140,10 +178,9 @@ if (IS_PRODUCTION) {
|
||||
app.use(express.static(distPath));
|
||||
// Fallback für Vue Router (SPA) - muss am Ende stehen
|
||||
app.get('*', (req, res) => {
|
||||
// Überspringe SEO-Routes in Production (werden bereits von setupSEORoutes behandelt)
|
||||
if (IS_PRODUCTION && (req.path === '/' || req.path === '/partners' || req.path === '/feedback' || req.path === '/faq' || req.path === '/regeln' || req.path === '/sicherheit')) {
|
||||
return; // Route wurde bereits behandelt
|
||||
}
|
||||
// Hinweis: SEO-Routen (/, /partners, …) werden bereits von setupSEORoutes registriert
|
||||
// und greifen vor diesem Catch-All. Kein frühes return ohne res.* hier.
|
||||
|
||||
// In Production: /src/ Pfade sollten nicht existieren (404)
|
||||
if (IS_PRODUCTION && req.path.startsWith('/src/')) {
|
||||
res.status(404).send('Not found');
|
||||
|
||||
@@ -283,11 +283,14 @@ export function setupSEORoutes(app, __dirname) {
|
||||
app.get(route, (req, res) => {
|
||||
const html = generateHTML(route, meta, __dirname);
|
||||
if (html) {
|
||||
// Zusätzliches kanonisches Signal (neben link rel= im HTML) – hilft Google bei der Zuordnung.
|
||||
res.set('Link', `<${meta.ogUrl}>; rel="canonical"`);
|
||||
res.send(html);
|
||||
return;
|
||||
}
|
||||
|
||||
if (existsSync(distIndexPath)) {
|
||||
res.set('Link', `<${meta.ogUrl}>; rel="canonical"`);
|
||||
res.sendFile(distIndexPath);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user