限制每次操作的可用HTTP谓词是一种好习惯吗?我的代码更清晰,没有[HttpGet]
,[HttpPost]
,[HttpPut]
或[HttpDelete]
装饰每个操作,但它可能也不那么健壮或安全。我没有在许多教程或示例代码中看到这一点,除非明确要求动词,例如有两个“创建”动作,其中GET版本返回一个新表单,POST版本插入一个新记录。
答案 0 :(得分:3)
我个人尝试尊重RESTful conventions并指定HTTP动词,但GET动作除外,它不会修改服务器上的任何状态,从而允许用任何HTTP动词调用它们。
答案 1 :(得分:1)
是的,我认为将您的操作仅限于它应该处理的相应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();
}
}
}
答案 2 :(得分:0)
您无需指定HttpGet,您需要的其他所有