在Web API开发中,处理并发控制是一个常见的需求。当多个用户同时对同一数据进行操作时,如何确保数据的一致性和完整性是一个挑战。本文将介绍一种使用ETag和If-Match头来实现并发控制的方法。
首先,需要创建一个空的Web API项目,并在Startup类中添加MVC的服务和中间件。
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvcWithDefaultRoute();
}
以上代码展示了如何在Startup类中配置MVC服务和中间件。
接下来,需要添加一个控制器,该控制器包含GET和PUT方法,用于演示并发控制。
[Route("movies")]
public class MoviesController : Controller
{
const string ETAG_HEADER = "ETag";
const string MATCH_HEADER = "If-Match";
[HttpGet("{id}")]
public IActionResult Get(int id)
{
var model_from_db = new Movie
{
Id = 1,
Title = "Thunderball",
ReleaseYear = 1965,
};
var eTag = HashFactory.GetHash(model_from_db);
HttpContext.Response.Headers.Add(ETAG_HEADER, eTag);
if (HttpContext.Request.Headers.ContainsKey(MATCH_HEADER) &&
HttpContext.Request.Headers[MATCH_HEADER].RemoveQuotes() == eTag)
return new StatusCodeResult(StatusCodes.Status304NotModified);
return Ok(model_from_db);
}
[HttpPut("{id}")]
public IActionResult Put(int id, [FromBody]Movie model)
{
var model_from_db = new Movie
{
Id = 1,
Title = "Thunderball-changed",
ReleaseYear = 1965,
};
var eTag = HashFactory.GetHash(model_from_db);
HttpContext.Response.Headers.Add(ETAG_HEADER, eTag);
if (!HttpContext.Request.Headers.ContainsKey(MATCH_HEADER) ||
HttpContext.Request.Headers[MATCH_HEADER].RemoveQuotes() != eTag)
{
return new StatusCodeResult(StatusCodes.Status412PreconditionFailed);
}
return NoContent();
}
}
以上代码展示了如何创建一个包含GET和PUT方法的控制器。GET方法用于获取数据,并在响应头中添加ETag。PUT方法用于更新数据,如果ETag匹配,则允许更新;否则,返回412 Precondition Failed状态码。
使用Postman等工具发送GET请求,观察响应头中的ETag值。然后,使用这个ETag值发送PUT请求。
目标是确保用户不会覆盖其他用户在他们检索数据和提交更改之间的更改。实现这种并发控制是一个简单的两步过程:
1. GET:根据持有的数据添加一个魔术值到响应中。通常,ETag头用于此目的,包含基于响应数据/主体的哈希值。
2. PUT:比较当前数据生成的ETag,并在未更改的情况下发送304(未修改)响应。
3. 如果更改了,发送412(前提条件失败)响应。