【问题标题】:stackoverflow URL rewritestackoverflow URL重写
【发布时间】:2023-03-09 04:10:01
【问题描述】:

如果我们只输入问题 ID,那么 SO 如何执行 URL 重写?

questions/{id}/{whatever}

questions/{id}/{question-slug}

我已经使用 MVC 工作了一段时间,我让它工作(路由、动作、一切),以便它根据提供的 ID 选择正确的内容。

但是,{id} 之后的部分(slug 部分)与输入的内容相同。因此,如果有人输入了content/5/foobar,它将显示正确的内容,但会将foobar 留在其中。

在控制器中(或其他地方,请建议在哪里)我需要进入数据库并拉出正确的 slug,将其放入路由数据中,然后使用这些正确的数据执行重定向到相同的操作,我猜?

这是对执行结果覆盖的尝试。它可以工作,但不能在浏览器中重定向或替换/显示正确的 URL:

    protected override void Execute(System.Web.Routing.RequestContext requestContext) {

        if (requestContext.RouteData.Values["id"] != null) {
            string currentSlug = _repository.Find(int.Parse(requestContext.RouteData.Values["id"].ToString())).Slug;
            if (requestContext.RouteData.Values["slug"] != null) {
                requestContext.RouteData.Values.Remove("slug");
            }
            requestContext.RouteData.Values.Add("slug", currentSlug);
        }

        base.Execute(requestContext);
    }

这是 Display 操作的另一个运行良好的版本,因此您可以看到它的作用并了解我想要什么:

    //
    // GET: {culture}/directory/5/{slug}
    public virtual ActionResult Display(int id, string slug)
    {
        var model = _repository.Find(id);
        if (model != null) {
            if (!model.Slug.Equals(slug, System.StringComparison.OrdinalIgnoreCase)) {
                return RedirectToActionPermanent(pndng.DirectoryEntry.ActionNames.Display, pndng.DirectoryEntry.Name, new { id = model.Id, slug = model.Slug });
            }
            return View(model);
        }
        // no model found
        return InvokeHttp404(HttpContext);
    }

这个执行永久重定向(它做我想要的)但它是对的吗? 我想我需要重定向来刷新浏览器 URL,不是吗?

【问题讨论】:

标签: asp.net-mvc routing asp.net-mvc-routing


【解决方案1】:
  public ActionResult Details(int id, string slug)
        {
            var session = MvcApplication.CurrentRavenSession;

            var blogPostRelations = session
                .Query<BlogPost, BlogPosts_WithRelatedData>()
                .Where(x => x.IntId == id)
                .As<BlogPostRelations>()
                .FirstOrDefault()
                ;


            if (blogPostRelations == null)
                return HttpNotFound();

            if (blogPostRelations.BlogPost.DisplayData.Slug.Value != slug)
                return RedirectToActionPermanent("Details", new { id = id, slug = blogPostRelations.BlogPost.DisplayData.Slug.Value });

            return View(blogPostRelations);
        }

注意:

if (blogPostRelations.BlogPost.DisplayData.Slug.Value != slug)
                    return RedirectToActionPermanent("Details", new { id = id, slug = blogPostRelations.BlogPost.DisplayData.Slug.Value });

所以你的第二个方法是正确的。

【讨论】:

    【解决方案2】:

    您可以为此编写自定义路由:

    public class QuestionsRoute : Route
    {
        public QuestionsRoute()
            : base(
                "questions/{id}/{slug}",
                new RouteValueDictionary(new
                {
                    controller = "questions",
                    action = "index",
                    slug = UrlParameter.Optional
                }),
                new RouteValueDictionary(new
                {
                    id = @"\d+"
                }),
                new MvcRouteHandler()
            )
        { }
    
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            var rd = base.GetRouteData(httpContext);
            if (rd == null)
            {
                return null;
            }
    
            var id = rd.GetRequiredString("id");
            var slug = rd.Values["slug"] as string;
            if (string.IsNullOrEmpty(slug))
            {
                slug = GoFetchSlugFromDb(id);
                if (string.IsNullOrEmpty(slug))
                {
                    return null;
                }
    
                httpContext.Response.RedirectToRoutePermanent(new
                {
                    action = "index",
                    controller = "questions",
                    id = id,
                    slug = slug
                });
                return null;
            }
            return rd;
        }
    
        private string GoFetchSlugFromDb(string id)
        {
            // TODO: you know what to do here
            throw new NotImplementedException();
        }
    }
    

    将在Application_Start注册:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.Add("questions", new QuestionsRoute());
    }
    

    现在您的 QuestionsController 将非常简单:

    public class QuestionsController: Controller
    {
        public ActionResult Index(int id, string slug)
        {
            ...
        }
    }
    

    【讨论】:

    • 不错的选择,在某些情况下很有用,但现在我将继续使用更简单的解决方案
    猜你喜欢
    • 2014-04-09
    • 2011-07-20
    • 2012-02-28
    • 1970-01-01
    • 2014-04-04
    • 2019-01-10
    • 1970-01-01
    • 1970-01-01
    • 2015-01-01
    相关资源
    最近更新 更多