如何在 mvc core 3.1 中显示 seo 友好 url?
How to show seo friendly url in mvc core 3.1?
我正在开发 mvc 核心 3.1 应用程序。 Seo 要求是显示带有主站点的产品名称而不是完整的 url.
我原来的url是
www.abc.com/Fashion/ProductDetail?productId=5088&productName=AliviaBlack&brandId=3
要求是
www.abc.com/alivia-black
我试过使用属性路由进行跟踪
endpoints.MapControllerRoute(
name: "SpecificRoute",
pattern: "/{productName}",
defaults: new { controller = "Fashion", action = "ProductDetail", id= "{productId}" });
在查看页面中
<a asp-route-productId="@product.ProductId"
asp-route-productName="@Common.FilterURL(product.ProductName)"
asp-route-brandId="@product.FashionBrand.FashionBrandId" asp-route="SpecificRoute">
结果是
www.abc.com/alivia-black?productId=5223&brandId=4
问号后面的参数怎么去掉
首先,URI 需要有弹性。您说您当前的要求是具有这样的 URI:
www.abc.com/alivia-black
即:
{host}/{productName}
这是一个非常糟糕的 URI 模板,因为:
- 它不会唯一地 标识产品(因为您可能有多个同名产品)。
- 如果您重命名产品或替换具有相同名称的产品,它将破坏来自外部网站的现有 link。这种情况 在任何产品数据库中都经常发生 。
- 因为您将
{productName}
放在 URI 结构的“根”中,这意味着除了查看产品(例如如何你会有一个 /contact-us
页面吗?如果你有一个名为 contact-us
的产品怎么办?)
我强调在 URI 中包含所请求实体的不可变键(在本例中为您的 productId
值)并将其用作主要参考非常重要,因此 productName
在处理传入的 HTTP 请求时可以忽略。这就是 Whosebug 和 Amazon 的 URI 的工作方式(您可以 trim 在 Whosebug 的问题 ID 后关闭文本,它仍然有效:例如
I strongly recommend you read this article on the W3.org's website all about designing good URIs, as well as other guidance from that group's homepage.
我建议你使用一个更好的 URI 模板,比如这个:
{host}/products/{productId}/{productName}
这会给你一个像这样的 URI:
abc.com/products/5088/alivablack
在 ASP.NET MVC(和 ASP.NET 核心)中处理这样的 link 是微不足道的,只需在控制器操作上设置路由模板:
[Route( "/products/{productId:int}/{productName?}" )]
public async Task<IActionResult> ShowProduct( Int32 productId, String? productName = null )
{
// Use `productId` to lookup the product.
// Disregard `productName` unless you want to use it as a fallback to search your database if `productId` doesn't work.
}
至于生成 URI,我建议反对 使用 TagHelpers(例如 <a asp-route-
),因为它们不提供您可以充分控制 URI 的呈现方式,您可以定义一个 UrlHelper
扩展方法(确保您 @import
将命名空间 .cshtml
页面(或将其添加到 ViewStart
):
public static class MyUrls
{
public static String ShowProduct( this IUrlHelper u, Int32 productId, String productName )
{
const String ACTION_NAME = nameof(ProductsController.ShowProduct);
const String CONTROLLER_NAME = "Products"; // Unfortunately we can't use `nameof` here due to the "Controller" suffix in the type-name.
String url = u.Action( action: ACTION_NAME, controller: CONTROLLER_NAME, values: new { productId = productId, productName = productName } );
return url;
}
}
然后就可以这样使用了:
<a href="@Urls.ShowProduct( 5088, "aliviablack" )">View AliviaBlack</a>
您还可以让 ShowProduct
直接接受您的 Product
对象之一,然后将值传递给另一个接受标量的重载(上面定义的):
public static String ShowProduct( this IUrlHelper u, Product product )
{
String url = ShowProduct( u, productId: product.ProductId, productName: product.ProductName );
return url;
}
然后你可以像这样使用它(假设 product
在范围内):
<a href="@Urls.ShowProduct( product )">@product.ProductName</a>
我正在开发 mvc 核心 3.1 应用程序。 Seo 要求是显示带有主站点的产品名称而不是完整的 url.
我原来的url是
www.abc.com/Fashion/ProductDetail?productId=5088&productName=AliviaBlack&brandId=3
要求是
www.abc.com/alivia-black
我试过使用属性路由进行跟踪
endpoints.MapControllerRoute(
name: "SpecificRoute",
pattern: "/{productName}",
defaults: new { controller = "Fashion", action = "ProductDetail", id= "{productId}" });
在查看页面中
<a asp-route-productId="@product.ProductId"
asp-route-productName="@Common.FilterURL(product.ProductName)"
asp-route-brandId="@product.FashionBrand.FashionBrandId" asp-route="SpecificRoute">
结果是
www.abc.com/alivia-black?productId=5223&brandId=4
问号后面的参数怎么去掉
首先,URI 需要有弹性。您说您当前的要求是具有这样的 URI:
www.abc.com/alivia-black
即:
{host}/{productName}
这是一个非常糟糕的 URI 模板,因为:
- 它不会唯一地 标识产品(因为您可能有多个同名产品)。
- 如果您重命名产品或替换具有相同名称的产品,它将破坏来自外部网站的现有 link。这种情况 在任何产品数据库中都经常发生 。
- 因为您将
{productName}
放在 URI 结构的“根”中,这意味着除了查看产品(例如如何你会有一个/contact-us
页面吗?如果你有一个名为contact-us
的产品怎么办?)
我强调在 URI 中包含所请求实体的不可变键(在本例中为您的 productId
值)并将其用作主要参考非常重要,因此 productName
在处理传入的 HTTP 请求时可以忽略。这就是 Whosebug 和 Amazon 的 URI 的工作方式(您可以 trim 在 Whosebug 的问题 ID 后关闭文本,它仍然有效:例如
I strongly recommend you read this article on the W3.org's website all about designing good URIs, as well as other guidance from that group's homepage.
我建议你使用一个更好的 URI 模板,比如这个:
{host}/products/{productId}/{productName}
这会给你一个像这样的 URI:
abc.com/products/5088/alivablack
在 ASP.NET MVC(和 ASP.NET 核心)中处理这样的 link 是微不足道的,只需在控制器操作上设置路由模板:
[Route( "/products/{productId:int}/{productName?}" )]
public async Task<IActionResult> ShowProduct( Int32 productId, String? productName = null )
{
// Use `productId` to lookup the product.
// Disregard `productName` unless you want to use it as a fallback to search your database if `productId` doesn't work.
}
至于生成 URI,我建议反对 使用 TagHelpers(例如 <a asp-route-
),因为它们不提供您可以充分控制 URI 的呈现方式,您可以定义一个 UrlHelper
扩展方法(确保您 @import
将命名空间 .cshtml
页面(或将其添加到 ViewStart
):
public static class MyUrls
{
public static String ShowProduct( this IUrlHelper u, Int32 productId, String productName )
{
const String ACTION_NAME = nameof(ProductsController.ShowProduct);
const String CONTROLLER_NAME = "Products"; // Unfortunately we can't use `nameof` here due to the "Controller" suffix in the type-name.
String url = u.Action( action: ACTION_NAME, controller: CONTROLLER_NAME, values: new { productId = productId, productName = productName } );
return url;
}
}
然后就可以这样使用了:
<a href="@Urls.ShowProduct( 5088, "aliviablack" )">View AliviaBlack</a>
您还可以让 ShowProduct
直接接受您的 Product
对象之一,然后将值传递给另一个接受标量的重载(上面定义的):
public static String ShowProduct( this IUrlHelper u, Product product )
{
String url = ShowProduct( u, productId: product.ProductId, productName: product.ProductName );
return url;
}
然后你可以像这样使用它(假设 product
在范围内):
<a href="@Urls.ShowProduct( product )">@product.ProductName</a>