大文字と小文字を区別しないURLとデフォルトが原因でASP.NET MVCでコンテンツが重複しないようにするにはどうすればよいですか?
-
05-07-2019 - |
質問
編集:この問題を実際に解決する必要がありますが、もう少しやりました 調査し、思いついた 重複を減らすことの数 コンテンツ。詳細なコードを投稿しました 私のブログのサンプル: Reducing ASP.NET MVCを使用したコンテンツの複製
最初の投稿-これを間違ってマークしたか、間違ってタグ付けした場合は簡単に実行してください:P
Microsoftの新しいASP.NET MVCフレームワークでは、コンテンツが複数のURL(Googleがペナルティを科し、PageRankが複数のURLに分割される原因になる)を引き起こす可能性がある2つのことがあるようです:
- 大文字と小文字を区別しないURL
- デフォルトURL
デフォルトのコントローラー/アクションを設定して、ドメインのルートへのリクエストに対応できます。 HomeController / Indexを選択したとしましょう。同じコンテンツを提供する次のURLになります:
- mydomain.com /
- mydomain.com/Home/Index
これらの両方へのリンクを開始すると、PageRankは分割されます。 Googleはまた、コンテンツの重複を考慮し、結果の重複を避けるためにそれらの1つを罰します。
さらに、URLでは大文字と小文字が区別されないため、実際にはこれらのURLでも同じコンテンツが取得されます。
- mydomain.com/Home/Index
- mydomain.com/home/index
- mydomain.com/Home/index
- mydomain.com/home/Index
- (リストが続きます)
では、質問...これらの罰則を回避するにはどうすればよいですか?欲しい:
- デフォルトアクションのすべてのリクエスト(301ステータス)を同じURLにリダイレクトする
- 大文字と小文字を区別するすべてのURL
可能ですか?
解決
バンプ!
MVC 5 小文字のURLと一般的な末尾のスラッシュポリシーのみの生成をサポートするようになりました。
public static void RegisterRoutes(RouteCollection routes)
{
routes.LowercaseUrls = true;
routes.AppendTrailingSlash = false;
}
また、アプリケーションでは、異なるドメイン/ IP /レターケースなどでコンテンツが重複しないようにします...
PrimaryDomain - Protocol - Controller - Language -アクション
public static String GetCanonicalUrl(RouteData route,String host,string protocol)
{
//These rely on the convention that all your links will be lowercase!
string actionName = route.Values["action"].ToString().ToLower();
string controllerName = route.Values["controller"].ToString().ToLower();
//If your app is multilanguage and your route contains a language parameter then lowercase it also to prevent EN/en/ etc....
//string language = route.Values["language"].ToString().ToLower();
return String.Format("{0}://{1}/{2}/{3}/{4}", protocol, host, language, controllerName, actionName);
}
その後、 @Gabe Sumnerの回答を使用して、現在のリクエストURLが一致しない場合、アクションの標準URLにリダイレクトできます。
他のヒント
私もこれに取り組んでいました。私は明らかにこれについてScottGuに従うでしょう。ただし、この問題に対する解決策も謙虚に提供します。
次のコードを global.asax に追加します。
protected void Application_BeginRequest(Object sender, EventArgs e)
{
// If upper case letters are found in the URL, redirect to lower case URL.
if (Regex.IsMatch(HttpContext.Current.Request.Url.ToString(), @"[A-Z]") == true)
{
string LowercaseURL = HttpContext.Current.Request.Url.ToString().ToLower();
Response.Clear();
Response.Status = "301 Moved Permanently";
Response.AddHeader("Location",LowercaseURL);
Response.End();
}
}
素晴らしい質問!
ここに投稿するだけでなく、私はScottGuにメールを送って、彼が良い反応を見せたかどうかを確認しました。彼はルートに制約を追加するためのサンプルを提供したので、小文字のURLにのみ応答できました:
public class LowercaseConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
string value = (string)values[parameterName];
return Equals(value, value.ToLower());
}
そして、ルートの登録方法:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "home", action = "index", id = "" },
new { controller = new LowercaseConstraint(), action = new LowercaseConstraint() }
);
}
これはスタートですが、Html.ActionLinkやRedirectToActionなどのメソッドからのリンクの生成を一致するように変更できるようにしたいと考えています。
これにはもっと良い答えがあると思います。次のような正規のリンクをページヘッドに挿入した場合:
<link rel="canonical" href="http://mydomain.com/Home/Index"/>
その後、Googleは結果に正規のページのみを表示し、さらに重要なことには、Googleのすべての良さがペナルティなしでそのページに反映されます。
同様に、同じ質問がありました。ただし、URLをすべて小文字に制限することを嫌がり、 canonical
アプローチも好きではありませんでした(それでいいのですが、それ自体ではありません)。
解決策が見つからなかったため、書き込みとオープンソース化 リダイレクトクラス。
それを使用するのは簡単です:コントローラークラスの各GETメソッドは、最初にこの1行だけを追加する必要があります:
Seo.SeoRedirect(this);
SEO書き換えクラスは自動的にC#5.0のCaller Info属性を使用して面倒な作業を行い、上記のコードを厳密にコピーアンドペーストします。
リンクされたSO Q&amp; Aで述べたように、これを属性に変換する方法に取り組んでいますが、今のところ、仕事は完了しています。
コードは、URLに対して1つのケースを強制します。大文字と小文字はコントローラーのメソッドの名前と同じです-すべて大文字にするか、すべて大文字にするか、両方を混在させるかを選択します(CamelCaseはURLに適しています)。大文字と小文字を区別しない一致に対して301リダイレクトを発行し、パフォーマンスを最適化するために結果をメモリにキャッシュします。また、末尾のバックスラッシュをリダイレクトし(インデックスリストの場合は強制され、そうでない場合は強制されます)、デフォルトのメソッド名(ストックASP.NET MVCアプリの Index
)を介してアクセスされる重複コンテンツを削除します。
8年後にどのように感じるか本当にわかりませんが、ASP MVC 5は属性ルーティングをサポートし、ルートを覚えやすく、SEOフレンドリーサイトの重複コンテンツの問題を解決します
追加するだけ routes.MapMvcAttributeRoutes(); RouteConfigで、次のような各アクションに対して1つだけのルートを定義します
[Route("~/")]
public ActionResult Index(int? page)
{
var query = from p in db.Posts orderby p.post_date descending select p;
var pageNumber = page ?? 1;
ViewData["Posts"] = query.ToPagedList(pageNumber, 7);
return View();
}
[Route("about")]
public ActionResult About()
{
return View();
}
[Route("contact")]
public ActionResult Contact()
{
return View();
}
[Route("team")]
public ActionResult Team()
{
return View();
}
[Route("services")]
public ActionResult Services()
{
return View();
}
Gabe Sumnerからの回答に基づいていますが、JS、画像、その他のコンテンツへのリダイレクトはありません。コントローラーアクションでのみ機能します。アイデアは、ルートが既にわかっているときに、パイプラインの後半でリダイレクトを行うことです。このために、ActionFilterを使用できます。
public class RedirectFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var url = filterContext.HttpContext.Request.Url;
var urlWithoutQuery = url.GetLeftPart(UriPartial.Path);
if (Regex.IsMatch(urlWithoutQuery, @"[A-Z]"))
{
string lowercaseURL = urlWithoutQuery.ToString().ToLower() + url.Query;
filterContext.Result = new RedirectResult(lowercaseURL, permanent: true);
}
base.OnActionExecuting(filterContext);
}
}
上記のフィルターは、クエリ文字列の大文字と小文字をリダイレクトまたは変更しないことに注意してください。
次に、ActionFilterをGlobalFilterCollectionに追加して、ActionFilterをすべてのアクションにグローバルにバインドします。
filters.Add(new RedirectFilterAttribute());
RouteCollectionでLowercaseUrlsプロパティをtrueに設定することをお勧めします。