Ограничение HTTP-глаголов при каждом действии - PullRequest
6 голосов
/ 28 апреля 2011

Полезно ли ограничивать доступные HTTP-глаголы для каждого действия?Мой код чище без [HttpGet], [HttpPost], [HttpPut] или [HttpDelete], не украшающих каждое действие, но он также может быть менее надежным или безопасным.Я не вижу этого во многих руководствах или примерах кода, если только глагол явно не требуется, например, наличие двух действий «Создать», когда версия GET возвращает новую форму, а версия POST вставляет новую запись.

Ответы [ 3 ]

3 голосов
/ 28 апреля 2011

Лично я стараюсь соблюдать RESTful-соглашения и указываю HTTP-глагол, за исключением действий GET, которые не изменяют состояние сервера, что позволяет им вызываться с любым HTTP-глаголом.

1 голос
/ 29 апреля 2011

Да, я считаю хорошей практикой ограничивать ваши действия только соответствующим HTTP-методом, который он должен обрабатывать, это предотвратит попадание плохих запросов в вашу систему, снизит эффективность возможных атак, улучшит документирование вашего кода,применять RESTful дизайн и т. д.

Да, использование атрибутов [HttpGet], [HttpPost] .. может затруднить чтение кода, особенно если вы также используете другие атрибуты, такие как [OutputCache], [Authorize]и т. д.

Я использую небольшой трюк с пользовательским IActionInvoker, вместо использования атрибутов, я добавляю метод HTTP к имени метода действия, например:

public class AccountController : Controller {

   protected override IActionInvoker CreateActionInvoker() {
      return new HttpMethodPrefixedActionInvoker();
   }

   public ActionResult GetLogOn() {
      ...
   }

   public ActionResult PostLogOn(LogOnModel model, string returnUrl) {
      ...
   }

   public ActionResult GetLogOff() {
      ...
   }

   public ActionResult GetRegister() {
      ...
   }

   public ActionResult PostRegister(RegisterModel model) {
      ...
   }

   [Authorize]
   public ActionResult GetChangePassword() {
      ...
   }

   [Authorize]
   public ActionResult PostChangePassword(ChangePasswordModel model) {
      ...
   }

   public ActionResult GetChangePasswordSuccess() {
      ...
   }
}

Обратите внимание, что этоне изменяет имена действий, которые по-прежнему LogOn, LogOff, Register и т. д.

Вот код:

using System;
using System.Collections.Generic;
using System.Web.Mvc;

public class HttpMethodPrefixedActionInvoker : ControllerActionInvoker {

   protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) {

      var request = controllerContext.HttpContext.Request;

      string httpMethod = request.GetHttpMethodOverride()
         ?? request.HttpMethod;

      // Implicit support for HEAD method. 
      // Decorate action with [HttpGet] if HEAD support is not wanted (e.g. action has side effects)

      if (String.Equals(httpMethod, "HEAD", StringComparison.OrdinalIgnoreCase))
         httpMethod = "GET";

      string httpMethodAndActionName = httpMethod + actionName;

      ActionDescriptor adescr = base.FindAction(controllerContext, controllerDescriptor, httpMethodAndActionName);

      if (adescr != null)
         adescr = new ActionDescriptorWrapper(adescr, actionName);

      return adescr;
   }

   class ActionDescriptorWrapper : ActionDescriptor {

      readonly ActionDescriptor wrapped;
      readonly string realActionName;

      public override string ActionName {
         get { return realActionName; }
      }

      public override ControllerDescriptor ControllerDescriptor {
         get { return wrapped.ControllerDescriptor; }
      }

      public override string UniqueId {
         get { return wrapped.UniqueId; }
      }

      public ActionDescriptorWrapper(ActionDescriptor wrapped, string realActionName) {

         this.wrapped = wrapped;
         this.realActionName = realActionName;
      }

      public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters) {
         return wrapped.Execute(controllerContext, parameters);
      }

      public override ParameterDescriptor[] GetParameters() {
         return wrapped.GetParameters();
      }

      public override object[] GetCustomAttributes(bool inherit) {
         return wrapped.GetCustomAttributes(inherit);
      }

      public override object[] GetCustomAttributes(Type attributeType, bool inherit) {
         return wrapped.GetCustomAttributes(attributeType, inherit);
      }

      public override bool Equals(object obj) {
         return wrapped.Equals(obj);
      }

      public override int GetHashCode() {
         return wrapped.GetHashCode();
      }

      public override ICollection<ActionSelector> GetSelectors() {
         return wrapped.GetSelectors();
      }

      public override bool IsDefined(Type attributeType, bool inherit) {
         return wrapped.IsDefined(attributeType, inherit);
      }

      public override string ToString() {
         return wrapped.ToString();
      }
   }
}
0 голосов
/ 28 апреля 2011

Вам не нужно указывать HttpGet, все остальные вам нужны

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...