2

考虑以下两个 POST 场景:

  1. POST /localhost/api/- 插入一个实体,返回 200
  2. POST /localhost/api/1324- 错误请求,返回 400

处理场景 2 的最佳方法是什么?

我是否什么都不做并假设使用我的 API 的开发人员会理解这是错误的?我是否在我的 POST 方法中添加代码来处理这个问题并告诉他们这是一个错误的请求?

我意识到返回一个错误的请求可能是最好的做法,这就是我最终实现的,但我觉得可能有更好的方法来实现这一点,但我还没有发现。

我当前的代码如下:

[HttpPost]
public HttpResponseMessage Post(MyEntity entity) {
  if(entity.Id != null)
      throw new HttpResponseException(HttpStatusCode.BadRequest);

  MyEntity saved = repository.Insert(entity);

  HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, saved);
  response.Headers.Location = new Uri(Request.RequestUri, new Uri(saved.Id.ToString(), UriKind.Relative));

  return response;
}

// Prevents any attempt to POST with a Guid in the url
[HttpPost]
public void Post(Guid Id) {
  throw new HttpResponseException(HttpStatusCode.BadRequest);
}

谢谢!

4

3 回答 3

3

你的所作所为似乎是有效的。虽然我有些怀疑我是否会这样做。

更正

我说过

如果您没有实现这个附加方法,那么路由将失败并且通常会返回 404。我很想将其保留为这种行为。

但你是对的:

要使其按上述方式运行,即默认为 404,您需要以下路由配置:

       config.Routes.MapHttpRoute(
            name: "DefaultCollectionApi",
            routeTemplate: "api/{controller}",
            defaults: new { },
            constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Post) }
            );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new {  },
            constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get, HttpMethod.Put, HttpMethod.Delete) }
            );

稍微改进您现有的方法

但是,如果您确实觉得需要开始监管动词和路由的组合,那么可能值得将此逻辑移动到 ActionFilterAttribute 中。

如果您在顶部添加此路由,那么它将 en 假设您"id"按惯例对所有路由使用,您可以快速组合一个过滤器,该过滤器RouteValues在键中查找值id并引发 400 异常。

public class ValidVerbAndRouteAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        object id;
        if (actionExecutedContext.ActionContext.ActionArguments.TryGetValue("id", out id) &&
            actionExecutedContext.Request.Method == HttpMethod.Post)
        {
            throw new HttpResponseException(HttpStatusCode.BadRequest);
        }
    }
} 
于 2013-02-26T12:38:18.687 回答
2

您目前处理它的方式似乎是正确的。它是标准输入数据验证,如果在 RESTful 术语中验证失败,则使用 400 是正确的状态代码。

于 2013-02-26T12:25:59.607 回答
1

您绑定的方式是正确的,但如果您愿意,还有另一种方式供您选择。您可以配置您的路线并声明应该调用具体操作,而不是您可以指定带有签名的操作,例如

[HttpPost]
public HttpResponseMessage PostEntity([FromBody]MyEntity entity) {...}

这将使对该操作的任何其他签名的调用变得不可能并导致异常。

路线:

            config.Routes.MapHttpRoute(
            name: "ActionApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional });

对于异常处理,我建议使用一个异常过滤器,其中包含一组异常类型的映射及其“HttpStatusCode”表示,根据您的喜好。

于 2013-02-26T12:41:45.840 回答