这取决于您在 API 中调用的版本,如果您将版本调用到实体的不同表示(xml、json 等),那么您应该使用接受标头或自定义标头。这就是 http 为处理表示而设计的方式。它是 RESTful 的,因为如果我同时调用同一个资源但请求不同的表示形式,返回的实体将具有完全相同的信息和属性结构但格式不同,这种版本控制是装饰性的。
另一方面,如果您将“版本”理解为实体结构的变化,例如将字段“年龄”添加到“用户”实体。然后你应该从资源的角度来处理这个问题,我认为这是 RESTful 方法。正如 Roy Fielding 在他的论文中所描述的那样...... REST 资源是从标识符到一组实体的映射......因此,在更改实体的结构时,您需要拥有指向该实体的适当资源是有道理的版本。这种版本控制是结构化的。
我在http://codebetter.com/howarddierking/2012/11/09/versioning-restful-services/中发表了类似的评论
在使用 url 版本控制时,版本应该在 url 中较晚而不是较早:
GET/DELETE/PUT onlinemall.com/grocery-store/customer/v1/{id}
POST onlinemall.com/grocery-store/customer/v1
另一种更简洁的方式,但在实施时可能会出现问题:
GET/DELETE/PUT onlinemall.com/grocery-store/customer.v1/{id}
POST onlinemall.com/grocery-store/customer.v1
这样做允许客户端专门请求他们想要映射到他们需要的实体的资源。不必弄乱在生产环境中实施时确实存在问题的标头和自定义媒体类型。
在 url 后面加上 url 可以让客户端在选择他们想要的资源时有更多的粒度,即使是在方法级别。
但从开发人员的角度来看,最重要的是,您不需要维护每个版本到所有资源和方法的整个映射(路径)。当您拥有大量子资源(嵌入式资源)时,这非常有价值。
从实现的角度来看,将其置于资源级别确实很容易实现,例如如果使用 Jersey/JAX-RS:
@Path("/customer")
public class CustomerResource {
...
@GET
@Path("/v{version}/{id}")
public IDto getCustomer(@PathParam("version") String version, @PathParam("id") String id) {
return locateVersion(version, customerService.findCustomer(id));
}
...
@POST
@Path("/v1")
@Consumes(MediaType.APPLICATION_JSON)
public IDto insertCustomerV1(CustomerV1Dto customer) {
return customerService.createCustomer(customer);
}
@POST
@Path("/v2")
@Consumes(MediaType.APPLICATION_JSON)
public IDto insertCustomerV2(CustomerV2Dto customer) {
return customerService.createCustomer(customer);
}
...
}
IDto 只是一个返回多态对象的接口,CustomerV1 和 CustomerV2 实现了该接口。