You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

nopCommerce 4.7.5产品URL结构修改:避免影响分类URL的方案

nopCommerce 4.7.5 产品详情页URL单独修改解决方案

需求:产品详情页URL改为 {host}/product/{productname},分类页及其他实体页面URL保持原有格式(如{host}/{分类名})。

问题根源:你当前的代码中,所有实体(产品、分类、厂商等)都共用了带/product/前缀的genericPattern,导致分类等页面也匹配到了带product的路由规则。

修改方案

核心思路是为产品单独定义带/product/前缀的路由模式,其他实体保留原始无前缀的模式,同时调整路由注册顺序,确保更具体的产品路由优先匹配。

修改后的RegisterRoutes代码如下:

public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
{
     var lang = GetLanguageRoutePattern();

     //default routes
     //these routes are not generic, they are just default to map requests that don't match other patterns, 
     //but we define them here since this route provider is with the lowest priority, to allow to add additional routes before them
     if (!string.IsNullOrEmpty(lang))
     {
         endpointRouteBuilder.MapControllerRoute(name: "DefaultWithLanguageCode",
             pattern: $"{lang}/{{controller=Home}}/{{action=Index}}/{{id?}}");
     }

     endpointRouteBuilder.MapControllerRoute(name: "Default",
         pattern: "{controller=Home}/{action=Index}/{id?}");

     if (!DataSettingsManager.IsDatabaseInstalled())
         return;

     // --- 拆分路由模式 ---
     // 产品专用带/product/前缀的模式
     var productGenericPattern = $"{lang}/product/{{{NopRoutingDefaults.RouteValue.SeName}}}";
     var productGenericCatalogPattern = $"{lang}/product/{{{NopRoutingDefaults.RouteValue.CatalogSeName}}}/{{{NopRoutingDefaults.RouteValue.SeName}}}";
     // 其他实体用的无前缀原始模式
     var genericPattern = $"{lang}/{{{NopRoutingDefaults.RouteValue.SeName}}}";
     var genericCatalogPattern = $"{lang}/{{{NopRoutingDefaults.RouteValue.CatalogSeName}}}/{{{NopRoutingDefaults.RouteValue.SeName}}}";

     // --- 注册动态路由 ---
     // 先注册产品的动态路由(优先级更高)
     endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(productGenericCatalogPattern);
     endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(productGenericPattern);
     // 再注册其他实体的动态路由
     endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(genericCatalogPattern);
     endpointRouteBuilder.MapDynamicControllerRoute<SlugRouteTransformer>(genericPattern);

     //routes for not found slugs
     if (!string.IsNullOrEmpty(lang))
     {
         // 产品的404路由
         endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.GenericProductUrlWithLanguageCode,
             pattern: productGenericPattern,
             defaults: new { controller = "Common", action = "GenericUrl" });

         endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.GenericProductCatalogUrlWithLanguageCode,
             pattern: productGenericCatalogPattern,
             defaults: new { controller = "Common", action = "GenericUrl" });

         // 其他实体的404路由
         endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.GenericUrlWithLanguageCode,
             pattern: genericPattern,
             defaults: new { controller = "Common", action = "GenericUrl" });

         endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.GenericCatalogUrlWithLanguageCode,
             pattern: genericCatalogPattern,
             defaults: new { controller = "Common", action = "GenericUrl" });
     }

     // 无语言码的404路由
     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.GenericUrl,
         pattern: $"{{{NopRoutingDefaults.RouteValue.SeName}}}",
         defaults: new { controller = "Common", action = "GenericUrl" });

     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.GenericCatalogUrl,
         pattern: $"{{{NopRoutingDefaults.RouteValue.CatalogSeName}}}/{{{NopRoutingDefaults.RouteValue.SeName}}}",
         defaults: new { controller = "Common", action = "GenericUrl" });

     // --- 绑定产品专属路由 ---
     //routes for entities that support catalog path and slug (e.g. '/category-seo-name/product-seo-name')
     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.ProductCatalog,
         pattern: productGenericCatalogPattern,
         defaults: new { controller = "Product", action = "ProductDetails" });

     //routes for entities that support single slug (e.g. '/product-seo-name')
     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.Product,
         pattern: productGenericPattern,
         defaults: new { controller = "Product", action = "ProductDetails" });

     // --- 其他实体使用原始无前缀路由 ---
     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.Category,
         pattern: genericPattern,
         defaults: new { controller = "Catalog", action = "Category" });

     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.Manufacturer,
         pattern: genericPattern,
         defaults: new { controller = "Catalog", action = "Manufacturer" });

     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.Vendor,
         pattern: genericPattern,
         defaults: new { controller = "Catalog", action = "Vendor" });

     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.NewsItem,
         pattern: genericPattern,
         defaults: new { controller = "News", action = "NewsItem" });

     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.BlogPost,
         pattern: genericPattern,
         defaults: new { controller = "Blog", action = "BlogPost" });

     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.Topic,
         pattern: genericPattern,
         defaults: new { controller = "Topic", action = "TopicDetails" });

     endpointRouteBuilder.MapControllerRoute(name: NopRoutingDefaults.RouteName.Generic.ProductTag,
         pattern: genericPattern,
         defaults: new { controller = "Catalog", action = "ProductsByTag" });
 }

关键改动说明

  1. 拆分路由模式:把原来的genericPattern拆分为productGenericPattern(带/product/)和genericPattern(无前缀),分别给产品和其他实体使用。
  2. 调整路由顺序:产品相关的动态路由和实体路由优先注册,确保请求先匹配产品的规则,避免分类等实体误匹配带product的路由。
  3. 独立404路由:为产品单独配置了404路由规则,和其他实体的404逻辑分开,避免冲突。

内容的提问来源于stack exchange,提问作者Drashti Kania

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 14:54:53