Angular 5路由如何实现URL大小写不敏感匹配?
I get it—coming from AngularJS + UI-Router, that one-line $urlMatcherFactory.caseInsensitive(true) was such a straightforward solution, and it’s annoying that Angular doesn’t have a built-in global switch for this. Let’s implement a clean, maintainable fix for your Angular 5 app that lets you keep Pascal-Case route declarations while accepting any case variation in URLs.
Option 1: Custom UrlMatcher (Recommended)
This approach gives you full control over route matching, supports routes with parameters, and avoids modifying URL serialization unless you need to.
Step 1: Create a Case-Insensitive UrlMatcher Function
First, write a matcher that compares URL segments to your route paths without case sensitivity:
import { UrlSegment, UrlSegmentGroup, Route, UrlMatchResult } from '@angular/router'; export function caseInsensitiveMatcher( url: UrlSegment[], group: UrlSegmentGroup, route: Route ): UrlMatchResult | null { const targetPath = route.path; if (!targetPath) return null; // Split route path and URL into segments const targetSegments = targetPath.split('/').filter(segment => segment); if (url.length !== targetSegments.length) return null; const params: { [key: string]: string } = {}; for (let i = 0; i < targetSegments.length; i++) { const targetSegment = targetSegments[i].toLowerCase(); const urlSegment = url[i].path.toLowerCase(); // Handle route parameters (e.g., :id) while preserving original case if (targetSegment.startsWith(':')) { const paramName = targetSegment.slice(1); params[paramName] = url[i].path; } // Check if non-param segments match (case-insensitive) else if (targetSegment !== urlSegment) { return null; } } return { consumed: url, posParams: params }; }
Step 2: Apply the Matcher to Routes
You can use this matcher for individual routes, or batch-convert all your routes to use it automatically:
import { Routes } from '@angular/router'; import { BusinessAccountManagementComponent } from './your-component-path'; import { caseInsensitiveMatcher } from './your-matcher-path'; // Original Pascal-Case route declarations const originalRoutes: Routes = [ { path: 'BusinessAccountManagement', component: BusinessAccountManagementComponent }, // Example with parameters { path: 'User/:userId', component: UserComponent }, // Add other routes here ]; // Batch convert routes to use case-insensitive matching function convertToCaseInsensitiveRoutes(routes: Routes): Routes { return routes.map(route => { const updatedRoute = { ...route }; // Add matcher only if path exists and no custom matcher is already set if (updatedRoute.path && !updatedRoute.matcher) { updatedRoute.matcher = caseInsensitiveMatcher; // Keep the original path for reference (optional) delete updatedRoute.path; } // Recursively apply to child routes if (updatedRoute.children) { updatedRoute.children = convertToCaseInsensitiveRoutes(updatedRoute.children); } return updatedRoute; }); } // Final routes to use in your RouterModule const routes: Routes = convertToCaseInsensitiveRoutes(originalRoutes);
Step 3 (Optional): Generate Pascal-Case URLs Internally
If you want routerLink or router.navigate to produce Pascal-Case URLs (instead of lowercase), customize the UrlSerializer:
import { DefaultUrlSerializer, UrlTree, UrlSerializer } from '@angular/router'; export class PascalCaseUrlSerializer extends DefaultUrlSerializer { // Map lowercase paths to your Pascal-Case route declarations private pathMappings: { [key: string]: string } = { 'businessaccountmanagement': 'BusinessAccountManagement', 'user': 'User' // Add mappings for all your routes }; serialize(tree: UrlTree): string { const rawUrl = super.serialize(tree); // Split URL into path and query params const [pathPart, queryPart] = rawUrl.split('?'); // Replace lowercase paths with Pascal-Case versions let formattedPath = pathPart; Object.entries(this.pathMappings).forEach(([lowerPath, pascalPath]) => { const regex = new RegExp(`/${lowerPath}(?=/)|/${lowerPath}$`, 'i'); formattedPath = formattedPath.replace(regex, `/${pascalPath}`); }); // Reattach query params if they exist return queryPart ? `${formattedPath}?${queryPart}` : formattedPath; } } // Provide the custom serializer in your AppModule export const PascalCaseUrlSerializerProvider = { provide: UrlSerializer, useClass: PascalCaseUrlSerializer };
Add the provider to your module's providers array:
@NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], providers: [PascalCaseUrlSerializerProvider] }) export class AppRoutingModule { }
Option 2: Simplified UrlSerializer Modification (For Basic Routes)
If your routes don’t have parameters and you want a quicker fix, modify your existing UrlSerializer to parse URLs to lowercase, then create a helper to convert your Pascal-Case route paths to lowercase during configuration:
// Update your LowerCaseUrlSerializer (unchanged from your original) export class LowerCaseUrlSerializer extends DefaultUrlSerializer { parse(url: string): UrlTree { return super.parse(url.toLowerCase()); } } export const LowerCaseUrlSerializerProvider = { provide: UrlSerializer, useClass: LowerCaseUrlSerializer }; // Helper to convert Pascal-Case routes to lowercase for matching function convertRoutesToLowerCase(routes: Routes): Routes { return routes.map(route => { const updatedRoute = { ...route }; if (updatedRoute.path) { updatedRoute.path = updatedRoute.path.toLowerCase(); } if (updatedRoute.children) { updatedRoute.children = convertRoutesToLowerCase(updatedRoute.children); } return updatedRoute; }); } // Use the helper with your original Pascal-Case routes const originalRoutes: Routes = [ { path: 'BusinessAccountManagement', component: BusinessAccountManagementComponent } ]; const routes: Routes = convertRoutesToLowerCase(originalRoutes);
Note: This won’t preserve Pascal-Case in generated URLs (they’ll be lowercase), so use Option 1 if you need that.
内容的提问来源于stack exchange,提问作者Bassem Mamar

