使用路由操作 url
Manipulate the url using routing
在我的网站中,我定义了以下路线:
routes.MapRoute(
name: "Specific Product",
url: "product/{id}",
defaults: new { controller = "", action = "Index", id = UrlParameter.Optional }
);
通过这种方式,我希望客户能够添加产品 ID 并转到产品页面。
SEO 顾问说,如果我们可以在 URL 上添加产品描述,例如产品名称或其他内容,那就更好了。所以 URL 应该看起来像:
/product/my-cool-product-name/123
或
/product/my-cool-product-name-123
当然,描述存储在数据库中,我无法通过 url 重写(或者我可以吗?)
我是否应该在我的控制器上添加重定向(这似乎可以完成工作,但感觉不对)
在我检查过的几个网站上,它们确实以 301 Moved Permanently
响应。这真的是最好的方法吗?
更新
根据 Stephen Muecke
的评论,我检查了 SO 上发生的事情。
建议的 url 是我自己的 ,我打开控制台查看任何重定向。这是屏幕截图:
所以,首先要特别感谢 @StephenMuecke 提供了 slug 的提示以及他建议的 url。
我想 post 我的方法是 url 和其他几篇文章的混合。
我的目标是让用户输入 url 比如:
/product/123
并且当页面加载时在地址栏中显示如下内容:
/product/my-awsome-product-name-123
我检查了几个有这种行为的网站,似乎我检查的所有网站都使用了 301 Moved Permanently
响应。即使是我的问题中显示的 SO,也使用 301
添加问题的标题。我认为会有一种不同的方法不需要第二次往返....
所以我在这种情况下使用的总解决方案是:
我创建了一个 SlugRouteHandler
class 看起来像:
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
class 来处理重定向。这实际上是 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 个 classes,我可以将产品 ID 转换为 SEO 友好 urls。
为了使用这些,我需要修改我的路线以使用 SlugRouteHandler
class,这导致:
从路线
呼叫SlugRouteHandler
class
routes.MapRoute(
name: "Specific Product",
url: "product/{slug}",
defaults: new { controller = "Product", action = "Index" }
).RouteHandler = new SlugRouteHandler();
他评论中提到的link@StephenMuecke的用法来了。
我们需要找到一种方法将新的 SEO 友好 url 映射到我们的实际控制者。我的控制器接受一个整数 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 并提供其视图,而无需修改控制器的内容。我们只需要在控制器上添加过滤器属性,如下一步所示。
我真的不在乎产品名称是否真的是产品名称。您可以尝试获取以下 urls:
\product3
\product\product-name-123
\product\another-product-123
\product\john-doe-123
你仍然会得到 ID 为 123
的产品,尽管 url 不同。
下一步是让控制器知道它必须使用特殊的文件管理器
[SlugToId]
public ActionResult Index(int id)
{
}
在我的网站中,我定义了以下路线:
routes.MapRoute(
name: "Specific Product",
url: "product/{id}",
defaults: new { controller = "", action = "Index", id = UrlParameter.Optional }
);
通过这种方式,我希望客户能够添加产品 ID 并转到产品页面。
SEO 顾问说,如果我们可以在 URL 上添加产品描述,例如产品名称或其他内容,那就更好了。所以 URL 应该看起来像:
/product/my-cool-product-name/123
或
/product/my-cool-product-name-123
当然,描述存储在数据库中,我无法通过 url 重写(或者我可以吗?)
我是否应该在我的控制器上添加重定向(这似乎可以完成工作,但感觉不对)
在我检查过的几个网站上,它们确实以 301 Moved Permanently
响应。这真的是最好的方法吗?
更新
根据 Stephen Muecke
的评论,我检查了 SO 上发生的事情。
建议的 url 是我自己的
所以,首先要特别感谢 @StephenMuecke 提供了 slug 的提示以及他建议的 url。
我想 post 我的方法是 url 和其他几篇文章的混合。
我的目标是让用户输入 url 比如:
/product/123
并且当页面加载时在地址栏中显示如下内容:
/product/my-awsome-product-name-123
我检查了几个有这种行为的网站,似乎我检查的所有网站都使用了 301 Moved Permanently
响应。即使是我的问题中显示的 SO,也使用 301
添加问题的标题。我认为会有一种不同的方法不需要第二次往返....
所以我在这种情况下使用的总解决方案是:
我创建了一个
SlugRouteHandler
class 看起来像: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
class 来处理重定向。这实际上是 herepublic 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 个 classes,我可以将产品 ID 转换为 SEO 友好 urls。
为了使用这些,我需要修改我的路线以使用 SlugRouteHandler
class,这导致:
从路线
呼叫SlugRouteHandler
classroutes.MapRoute( name: "Specific Product", url: "product/{slug}", defaults: new { controller = "Product", action = "Index" } ).RouteHandler = new SlugRouteHandler();
他评论中提到的link@StephenMuecke的用法来了。
我们需要找到一种方法将新的 SEO 友好 url 映射到我们的实际控制者。我的控制器接受一个整数 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 并提供其视图,而无需修改控制器的内容。我们只需要在控制器上添加过滤器属性,如下一步所示。
我真的不在乎产品名称是否真的是产品名称。您可以尝试获取以下 urls:
\product3
\product\product-name-123
\product\another-product-123
\product\john-doe-123
你仍然会得到 ID 为 123
的产品,尽管 url 不同。
下一步是让控制器知道它必须使用特殊的文件管理器
[SlugToId] public ActionResult Index(int id) { }