在我的网站中,我定义了以下路线:
routes.MapRoute(
name: "Specific Product",
url: "product/{id}",
defaults: new { controller = "", action = "Index", id = UrlParameter.Optional }
);
这样我希望客户能够添加产品的ID并转到产品页面。
SEO顾问说,如果我们可以在URL上添加产品描述(如产品名称或其他内容)会更好。因此,URL应如下所示:
/产品/我的 - 冷却 - 产品名称/ 123
或
/产品/我的 - 冷却 - 产品名称-123
当然描述存储在db中,我不能用url重写(或者我可以吗?)
我应该在控制器上添加重定向(这似乎可以完成工作,但它感觉不对)
在我检查过的几个网站上,他们确实回复了301 Moved Permanently
。这真的是最好的方法吗?
更新
根据Stephen Muecke
的评论,我查看了SO上发生的事情。
建议的网址是我自己的Manipulate the url using routing,我打开控制台查看任何重定向。这是一个截图:
答案 0 :(得分:0)
所以,首先非常特别感谢 @StephenMuecke 给出了slug的提示以及他建议的网址。
我想发布我的方法,该方法是该网址和其他几篇文章的混合。
我的目标是让用户输入一个网址:
/产品/ 123
当页面加载以在地址栏中显示如下内容:
/产品/ MY-要命产品名称-123
我检查了几个有此行为的网站,似乎在我检查的所有内容中都使用了301 Moved Permanently
响应。即便如我在问题中所示,使用301
来添加问题的标题。我认为会有一种不同的方法,不需要第二次往返......
所以我在这种情况下使用的总解决方案是:
我创建了一个SlugRouteHandler
类,如下所示:
public class SlugRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var url = requestContext.HttpContext.Request.Path.TrimStart('/');
if (!string.IsNullOrEmpty(url))
{
var slug = (string)requestContext.RouteData.Values["slug"];
int id;
//i care to transform only the urls that have a plain product id. If anything else is in the url i do not mind, it looks ok....
if (Int32.TryParse(slug, out id))
{
//get the product from the db to get the description
var product = dc.Products.Where(x => x.ID == id).FirstOrDefault();
//if the product exists then proceed with the transformation.
//if it does not exist then we could addd proper handling for 404 response here.
if (product != null)
{
//get the description of the product
//SEOFriendly is an extension i have to remove special characters, replace spaces with dashes, turn capital case to lower and a whole bunch of transformations the SEO audit has requested
var description = String.Concat(product.name, "-", id).SEOFriendly();
//transform the url
var newUrl = String.Concat("/product/",description);
return new RedirectHandler(newUrl);
}
}
}
return base.GetHttpHandler(requestContext);
}
}
从上面我还需要创建一个RedirectHandler
类来处理重定向。这实际上是here
public class RedirectHandler : IHttpHandler
{
private string newUrl;
public RedirectHandler(string newUrl)
{
this.newUrl = newUrl;
}
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext httpContext)
{
httpContext.Response.Status = "301 Moved Permanently";
httpContext.Response.StatusCode = 301;
httpContext.Response.AppendHeader("Location", newUrl);
return;
}
}
通过这2个课程,我可以将产品ID转换为SEO友好的网址。
为了使用这些我需要修改我的路线以使用SlugRouteHandler
类,这导致:
从路径
调用SlugRouteHandler
课程
routes.MapRoute(
name: "Specific Product",
url: "product/{slug}",
defaults: new { controller = "Product", action = "Index" }
).RouteHandler = new SlugRouteHandler();
使用评论中提到的link @StephenMuecke 。
我们需要找到一种方法将新的SEO友好网址映射到我们的实际控制器。我的控制器接受一个整数id,但url将提供一个字符串。
我们需要创建一个Action过滤器来处理在调用控制器之前传递的新参数
public class SlugToIdAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var slug = filterContext.RouteData.Values["slug"] as string;
if (slug != null)
{
//my transformed url will always end in '-1234' so i split the param on '-' and get the last portion of it. That is my id.
//if an id is not supplied, meaning the param is not ending in a number i will just continue and let something else handle the error
int id;
Int32.TryParse(slug.Split('-').Last(), out id);
if (id != 0)
{
//the controller expects an id and here we will provide it
filterContext.ActionParameters["id"] = id;
}
}
base.OnActionExecuting(filterContext);
}
}
现在发生的事情是控制器将能够接受以数字结尾的非数字id并提供其视图而不修改控制器的内容。我们只需要在控制器上添加filter属性,如下一步所示。
我真的不在乎产品名称是否实际上是产品名称。您可以尝试获取以下网址:
\产品\ 123
\产品\产品名称-123
\产品\另一副产物-123
\产品\约翰-DOE-123
并且您仍会获得ID为123
的产品,但网址不同。
下一步是让控制器知道它必须使用特殊的文件管理器
[SlugToId]
public ActionResult Index(int id)
{
}