将特殊字符重定向到它们的 "escaped URL form"
Redirect special characters to their "escaped URL form"
我网站上的 URL (ASP.NET MVC 4.6) 如下所示:
/test/sog
但是,我的网站是丹麦语,所以我想在所有 URL 中将丹麦语特殊字符“ø”重定向到 'o'。
在上述情况下,对 /test/søg 的请求应该重定向到 /test/sog.
我的网站相当大,所以我想在整个网站范围内执行此操作(而不必为每个 URL 创建单独的重定向控制器方法)。
我该怎么做?
这是一个有趣的问题,我想知道答案。事实证明这是相当简单的。要实现这一点,您确实需要两件事。
- 将字符串转换为罗马字符。
- 执行 301 重定向到新 URL。
将字符串转换为罗马字符
我找到了答案here,但将其修改为扩展方法以使其更易于使用。
using System;
using System.Globalization;
using System.Text;
public static class StringExtensions
{
public static string RemoveDiacritics(this string text)
{
var normalizedString = text.Normalize(NormalizationForm.FormD);
var stringBuilder = new StringBuilder();
foreach (var c in normalizedString)
{
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}
}
执行 301 重定向到新 URL
这有点复杂。虽然您 可以 进行 302 重定向(所有浏览器都遵守),但 301 对 SEO 更友好,所以这就是我在这里展示的方法。遗憾的是,某些浏览器不会自动遵循 301 重定向。因此,需要一些额外的步骤来确保如果浏览器不这样做,用户将通过客户端 302 重定向进行重定向,如果失败,则显示 link ,他们可以在其中跳转到下一页.
RedirectToRomanizedUrlPermanent.cs
我们首先使用一条路线来清洁 URL。如果干净的 URL 与原来的不同(即替换了一个或多个字符),我们将请求发送到名为 SystemController
的控制器来处理 301 重定向。
public class RedirectToRomanizedUrlPermanent : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var path = httpContext.Request.Path;
var romanPath = path.RemoveDiacritics();
if (!path.Equals(romanPath, StringComparison.OrdinalIgnoreCase))
{
var routeData = new RouteData(this, new MvcRouteHandler());
routeData.Values["controller"] = "System";
routeData.Values["action"] = "Status301";
routeData.DataTokens["redirectLocation"] = romanPath;
return routeData;
}
return null;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
return null;
}
}
SystemController.cs
接下来,我们有我们的控制器,其目的是实际提供 301 状态。如果浏览器不遵守 301,则会向用户显示一个视图。
using System.Net;
using System.Web.Mvc;
public class SystemController : Controller
{
public ActionResult Status301()
{
var redirectLocation = this.Request.RequestContext.RouteData.DataTokens["redirectLocation"] as string;
// IMPORTANT: Don't cache the 301 redirect because browsers tend to keep it around
// meaning you cannot update the browser to a different URL from the server side.
Response.CacheControl = "no-cache";
Response.StatusCode = (int)HttpStatusCode.MovedPermanently;
Response.RedirectLocation = redirectLocation;
ViewBag.RedirectLocation = redirectLocation;
return View();
}
}
/Views/System/Status301.cshtml
视图将尝试通过 Meta-Refresh JavaScript 和 自动重定向用户。这两个都可以在浏览器中关闭,但用户很可能会把它带到他们应该去的地方。如果没有,您应该告诉用户:
- 该页面有一个新位置。
- 如果没有自动重定向,他们需要单击 link。
- 他们应该将书签更新到新的 URL。
@{
ViewBag.Title = "Page Moved";
}
@section MetaRefresh {
<meta http-equiv="refresh" content="5;@ViewBag.RedirectLocation" />
}
<h2 class="error">Page Moved</h2>
<p>
The page has a new location. Click on the following link if you are
not redirected automatically in 5 seconds. Please update your bookmark(s) to the new location.
</p>
<a href="@ViewBag.RedirectLocation">@ViewBag.RedirectLocation</a>.
<script>
//<!--
setTimeout(function () {
window.location = "@ViewBag.RedirectLocation";
}, 5000);
//-->
</script>
用法
向应用程序的 _Layout.cshtml
页面添加一个部分,以便元刷新可以放置在页面的 <head>
部分。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title - My ASP.NET MVC Application</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<!-- Add this so the view can update this section -->
@RenderSection("MetaRefresh", required: false)
<meta name="viewport" content="width=device-width" />
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<!-- layout code omitted -->
</html>
用 MVC 注册路由。重要的是,这发生在任何其他路由被注册之前(包括对 MapMvcAttributeRoutes
或 AreaRegistration.RegisterAllAreas
的任何调用)。
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// IMPORTANT: Register this before any other routes.
routes.Add(new RedirectToRomanizedUrlPermanent());
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
现在当您输入 URL 例如 /Ĥőmȩ/Ċőńţãçť
时,您会自动重定向到 /Home/Contact
。
我网站上的 URL (ASP.NET MVC 4.6) 如下所示: /test/sog
但是,我的网站是丹麦语,所以我想在所有 URL 中将丹麦语特殊字符“ø”重定向到 'o'。
在上述情况下,对 /test/søg 的请求应该重定向到 /test/sog.
我的网站相当大,所以我想在整个网站范围内执行此操作(而不必为每个 URL 创建单独的重定向控制器方法)。
我该怎么做?
这是一个有趣的问题,我想知道答案。事实证明这是相当简单的。要实现这一点,您确实需要两件事。
- 将字符串转换为罗马字符。
- 执行 301 重定向到新 URL。
将字符串转换为罗马字符
我找到了答案here,但将其修改为扩展方法以使其更易于使用。
using System;
using System.Globalization;
using System.Text;
public static class StringExtensions
{
public static string RemoveDiacritics(this string text)
{
var normalizedString = text.Normalize(NormalizationForm.FormD);
var stringBuilder = new StringBuilder();
foreach (var c in normalizedString)
{
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}
}
执行 301 重定向到新 URL
这有点复杂。虽然您 可以 进行 302 重定向(所有浏览器都遵守),但 301 对 SEO 更友好,所以这就是我在这里展示的方法。遗憾的是,某些浏览器不会自动遵循 301 重定向。因此,需要一些额外的步骤来确保如果浏览器不这样做,用户将通过客户端 302 重定向进行重定向,如果失败,则显示 link ,他们可以在其中跳转到下一页.
RedirectToRomanizedUrlPermanent.cs
我们首先使用一条路线来清洁 URL。如果干净的 URL 与原来的不同(即替换了一个或多个字符),我们将请求发送到名为 SystemController
的控制器来处理 301 重定向。
public class RedirectToRomanizedUrlPermanent : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var path = httpContext.Request.Path;
var romanPath = path.RemoveDiacritics();
if (!path.Equals(romanPath, StringComparison.OrdinalIgnoreCase))
{
var routeData = new RouteData(this, new MvcRouteHandler());
routeData.Values["controller"] = "System";
routeData.Values["action"] = "Status301";
routeData.DataTokens["redirectLocation"] = romanPath;
return routeData;
}
return null;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
return null;
}
}
SystemController.cs
接下来,我们有我们的控制器,其目的是实际提供 301 状态。如果浏览器不遵守 301,则会向用户显示一个视图。
using System.Net;
using System.Web.Mvc;
public class SystemController : Controller
{
public ActionResult Status301()
{
var redirectLocation = this.Request.RequestContext.RouteData.DataTokens["redirectLocation"] as string;
// IMPORTANT: Don't cache the 301 redirect because browsers tend to keep it around
// meaning you cannot update the browser to a different URL from the server side.
Response.CacheControl = "no-cache";
Response.StatusCode = (int)HttpStatusCode.MovedPermanently;
Response.RedirectLocation = redirectLocation;
ViewBag.RedirectLocation = redirectLocation;
return View();
}
}
/Views/System/Status301.cshtml
视图将尝试通过 Meta-Refresh JavaScript 和 自动重定向用户。这两个都可以在浏览器中关闭,但用户很可能会把它带到他们应该去的地方。如果没有,您应该告诉用户:
- 该页面有一个新位置。
- 如果没有自动重定向,他们需要单击 link。
- 他们应该将书签更新到新的 URL。
@{
ViewBag.Title = "Page Moved";
}
@section MetaRefresh {
<meta http-equiv="refresh" content="5;@ViewBag.RedirectLocation" />
}
<h2 class="error">Page Moved</h2>
<p>
The page has a new location. Click on the following link if you are
not redirected automatically in 5 seconds. Please update your bookmark(s) to the new location.
</p>
<a href="@ViewBag.RedirectLocation">@ViewBag.RedirectLocation</a>.
<script>
//<!--
setTimeout(function () {
window.location = "@ViewBag.RedirectLocation";
}, 5000);
//-->
</script>
用法
向应用程序的 _Layout.cshtml
页面添加一个部分,以便元刷新可以放置在页面的 <head>
部分。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title - My ASP.NET MVC Application</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<!-- Add this so the view can update this section -->
@RenderSection("MetaRefresh", required: false)
<meta name="viewport" content="width=device-width" />
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<!-- layout code omitted -->
</html>
用 MVC 注册路由。重要的是,这发生在任何其他路由被注册之前(包括对 MapMvcAttributeRoutes
或 AreaRegistration.RegisterAllAreas
的任何调用)。
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// IMPORTANT: Register this before any other routes.
routes.Add(new RedirectToRomanizedUrlPermanent());
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
现在当您输入 URL 例如 /Ĥőmȩ/Ċőńţãçť
时,您会自动重定向到 /Home/Contact
。