赞
踩
WebAPI是一种基于HTTP协议的网络应用程序接口,它使用JSON或XML格式来传输数据。WebAPI是服务器端应用程序,允许客户端应用程序通过HTTP请求来访问服务器上的数据。WebAPI支持RESTful服务,是构建这种服务的理想选择。同时,WebAPI的客户端系统和服务系统彼此独立,调用者可以使用不同的语言(如Java、Python、Ruby等)进行API的调用。
通过ASP.NET Web API框架,可以实现资源的创建(POST)、读取(GET)、更新(PUT/PATCH)和删除(DELETE)等操作,这些操作都遵循RESTful架构风格。以下是一个简单的步骤:
首先,需要在Visual Studio中创建一个ASP.NET Web API项目。通过选择“文件” -> “新建” -> “项目”,然后在项目模板中选择“ASP.NET Web 应用程序”来完成。在创建过程中,选择“Web API”作为项目类型。
模型类代表了你想要通过API操作的数据资源。例如,如果你想要操作一个用户资源,你可以定义一个User
类:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
控制器负责处理HTTP请求并返回响应。你需要创建一个继承自ApiController
的类,并添加与资源操作对应的方法。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using WebApplication1.Models; namespace WebApplication1.Controllers { [RoutePrefix("api/Test")] public class TestController : ApiController { // GET api/Test [HttpGet] [Route("GetUser")] public IEnumerable<User> GetUser() { // 返回所有用户的逻辑 return new List<User> { new User { Id = 1, Name = "Alice", Email = "alice@example.com" }, new User { Id = 2, Name = "Bob", Email = "bob@example.com" } // ... 其他用户数据 }; } // GET api/Test/5 [HttpGet] [Route("GetMyUser")] public User GetMyUser(int id) { // 根据ID返回单个用户的逻辑 return new User { Id = 1, Name = "Alice", Email = "alice@example.com" }; } // POST api/Test [HttpPost] [Route("PostUser")] public IHttpActionResult PostUser([FromBody] User user) { // 创建新用户的逻辑 if (!ModelState.IsValid) { return BadRequest(ModelState); } // 假设的创建新用户逻辑 bool success = true; if (success) { // 创建成功,返回201 Created状态码,并可能包含新用户的URI return Ok(user.Id+"创建成功!"); } else { // 创建失败,返回500 Internal Server Error状态码 return InternalServerError(); } } // PUT api/Test/5 [HttpPut] [Route("PutUser")] public IHttpActionResult PutUser(int id, [FromBody] User user) { // 更新指定ID的用户的逻辑 if (!ModelState.IsValid) { return BadRequest(ModelState); } if (id != user.Id) { return BadRequest("ID mismatch in the URL and the request body."); } // 假设的更新用户逻辑 bool success = true; if (success) { // 更新成功,返回204 No Content状态码 return Ok("成功"); } else { // 更新失败,返回500 Internal Server Error状态码 return InternalServerError(); } } // DELETE api/Test/5 [HttpDelete] [Route("DeleteUser")] public IHttpActionResult DeleteUser(int id) { // 删除指定ID的用户的逻辑 // 假设的删除用户逻辑 bool success = true; if (success) { // 删除成功,返回204 No Content状态码 return Ok("成功"); } else { // 如果未找到用户,返回404 Not Found状态码 if (false) { return NotFound(); } // 其他删除失败情况,返回500 Internal Server Error状态码 return InternalServerError(); } } } }
在Web API项目中,你需要配置路由以将HTTP请求映射到控制器的方法。这通常在WebApiConfig.cs
文件中完成,该文件位于App_Start
文件夹下。
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
运行Web API项目,并使用工具如Postman或浏览器来测试你的API。你可以发送GET、POST、PUT和DELETE请求到相应的URL,并观察响应。
例如,要获取所有用户,你可以发送一个GET请求到http://localhost:<port>/api/Test/GetUser
。要创建一个新用户,你可以发送一个POST请求到http://localhost:<port>/api/Test/PostUser
,并在请求体中包含用户数据。
使用ASP.NET Web API时,可以通过模型验证、异常过滤器以及其他机制来增强API的健壮性和安全性。
对于PostUser
和PutUser
方法,可以使用数据注解(Data Annotations)来定义模型验证规则。例如:
public class UserNew
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
public string Email { get; set; }
}
在API控制器中,可以检查模型状态(ModelState)是否有效:
[HttpPost] [Route("PostUserNew")] public IHttpActionResult PostUserNew([FromBody] UserNew user) { if (!ModelState.IsValid) { return BadRequest(ModelState); } // 假设用户创建逻辑... return Ok("用户创建成功"); } [HttpPut] [Route("PutUserNew")] public IHttpActionResult PutUserNew(int id, [FromBody] UserNew user) { if (!ModelState.IsValid) { return BadRequest(ModelState); } // 假设用户更新逻辑... return Ok("用户更新成功"); }
创建自定义的异常过滤器来处理未捕获的异常,并返回适当的HTTP响应。例如:
public class HttpExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext.Exception is Exception ex)
{
actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(
HttpStatusCode.InternalServerError, ex.Message);
}
}
}
然后,我们可以在控制器或全局范围内应用这个过滤器:
[HttpExceptionFilter]
public class TestController : ApiController
{
// ... 方法 ...
}
或者,在Web API配置中全局注册:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// ... 其他配置 ...
config.Filters.Add(new HttpExceptionFilterAttribute());
}
}
对于安全性,需要实施身份验证和授权机制。ASP.NET Web API支持多种身份验证方式,如OAuth 2.0、JWT等。可以使用内置的[Authorize]
属性来要求用户授权才能访问某些API。
为了防止跨站请求伪造攻击,应该考虑在API中实施防护措施,比如检查请求的来源或使用验证令牌。
对于所有从客户端接收的输入,都应该进行验证和清理,以防止SQL注入、跨站脚本(XSS)等攻击。可以使用ASP.NET中的安全功能,比如编码助手类,来清理和编码输出。
返回具体的错误信息或详细的堆栈跟踪可能会泄露敏感信息。在生产环境中,应只返回一般性的错误消息,并避免暴露内部实现细节。
实现良好的日志记录机制可以帮助你追踪问题、识别攻击和审计API的使用情况。可以使用ASP.NET的日志记录功能或第三方日志库。
完成开发和测试后,需要将Web API项目部署到IIS服务器或其他托管环境中,以便其他客户端应用程序可以访问它。
在前一篇中已经专门讲过HTTP协议,在此不多做赘述。
创建项目前面已经说过了,现在主要记录项目的基本结构和文件组成
WebApiConfig.cs
。AssemblyInfo.cs
和launchSettings.json
(对于ASP.NET Core项目)。wwwroot
(用于存放静态文件)或Dependencies
(包含项目依赖项)。Global.asax
包含应用程序的启动和关闭事件。对于ASP.NET Core,Startup.cs
类中的ConfigureServices
和Configure
方法用于配置服务和请求处理管道。ValuesController.cs
):控制器类,用于处理特定的HTTP请求。每个控制器通常对应一组相关的API端点。appsettings.json
(用于存储应用程序设置)和web.config
(用于IIS设置)。Global.asax
文件是一个非常重要的文件,它用于处理应用程序级别的事件,如应用程序启动、关闭以及会话启动和关闭等。对于Web API项目,通常会在 Global.asax
文件中配置路由规则。
下面是一个 Global.asax
文件的示例,演示了如何配置Web API的路由规则:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace WebApplication1 { public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } } }
在这个例子中,Application_Start
方法在应用程序启动时调用。GlobalConfiguration.Configure(WebApiConfig.Register);
这行代码是配置Web API路由的关键所在。它调用了 WebApiConfig
类中的 Register
方法来配置路由。
需要创建一个名为 WebApiConfig
的类,并在其中定义路由配置。下面是一个 WebApiConfig
类的示例:
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; using System.Web.Routing; namespace WebApplication1 { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服务 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }
在这个 WebApiConfig
类中,Register
方法定义了Web API的路由规则。config.MapHttpAttributeRoutes();
这行代码允许我们使用特性路由,即在控制器或动作方法上使用 [Route]
特性来定义路由。
config.Routes.MapHttpRoute
方法定义了一个默认的路由规则。在这个例子中,路由模板是 "api/{controller}/{id}"
,这意味着当我们访问像 api/Test 这样的URL时,它会映射到 TestController的默认动作方法(通常是 Get)。{id}是可选的,这意味着我们可以访问 api/Test/1
来获取特定ID的资源。
一旦定义了这些路由规则,Web API控制器就可以根据这些规则来处理HTTP请求了。例如,如果有一个名为 TestController
的控制器,并且我们想要处理GET请求来获取一组值,你可以这样定义它:
using System; using System.Collections.Generic; using System.Web.Http; namespace WebApplication1.Controllers { public class TestController : ApiController { // GET api/Test [HttpGet] [Route("Get")] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } // 其他动作方法... } }
跨域资源共享(CORS,Cross-Origin Resource Sharing)是一个重要概念,它允许Web应用程序从不同的源(域、协议或端口)访问资源。默认情况下,出于安全考虑,浏览器会限制从一个源加载的文档或脚本与另一个源的资源进行交互。但是,通过CORS,服务器可以明确指定哪些外部源有权访问其资源。
CORS是一个W3C规范,它定义了一种浏览器和服务器交互的方式来确定是否允许跨源请求。这主要通过服务器返回的HTTP响应头来实现。当浏览器发送一个跨域请求时,它会在请求头中包含Origin
字段,表示请求的源。服务器根据这个Origin
字段以及其他的CORS相关头信息(如Access-Control-Allow-Origin
),来决定是否允许这个请求。
在C# WebAPI (.NET Framework) 项目中,可以通过几种方式来启用和配置CORS:
3.2.1 使用Web.config文件
在Web.config
文件的<system.webServer>
部分,可以添加CORS相关的HTTP响应头。但是,这种方式不够灵活,且难以管理复杂的CORS策略。
3.2.2 使用全局CORS策略
在WebApiConfig.Register
方法中,可以配置全局的CORS策略。这通常是通过调用EnableCors
扩展方法来实现的。例如:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// ... 其他配置 ...
// 启用CORS支持并设置全局策略
var cors = new EnableCorsAttribute("*", "*", "*"); // 允许所有源、所有方法和所有头信息
config.EnableCors(cors); // 应用全局CORS策略
}
}
请注意,使用"*"
作为源、方法和头信息是一种非常宽松的策略,可能带来安全风险。在实际应用中,应该根据具体需求来限制这些值。
3.2.3 使用控制器或动作级别的CORS策略
除了全局策略外,还可以在控制器或动作级别上设置CORS策略。这可以通过在控制器或动作方法上使用[EnableCors]
特性来实现。例如:
[EnableCors(origins: "http://example.com", headers: "*", methods: "*")]
public class MyApiController : ApiController
{
// ... 控制器方法 ...
}
或者,只在特定的动作方法上应用CORS策略:
public class MyApiController : ApiController
{
[EnableCors(origins: "http://example.com", headers: "*", methods: "GET,POST")]
public IHttpActionResult MyAction()
{
// ... 动作方法实现 ...
}
}
在配置CORS时,务必注意安全性。不要随意允许所有源、方法和头信息,因为这可能使你的API暴露给潜在的攻击者。应该根据API的实际需求和安全策略来仔细设置CORS策略。
此外,即使启用了CORS,仍然需要确保API的其他安全措施(如身份验证、授权和输入验证)得到妥善实施,以防止未授权访问和数据泄露。
使用路由属性(如 [Route]
、[HttpGet]
、[HttpPost]
等)是定义和映射HTTP请求到特定控制器方法的一种非常方便的方式。这些特性允许你以声明式的方式指定如何路由到你的API方法,而不是依赖于全局路由配置。
下面是如何在WebAPI中使用这些路由属性的示例:
在控制器类上使用 [Route]
特性,你可以定义一个基础路由前缀,该前缀将应用于控制器中的所有方法。
[RoutePrefix("api/Test")]
public class TestController : ApiController
{
// 控制器方法将映射到以 "api/Test" 为前缀的路由
}
在控制器的方法上使用 [Route]
特性,可以定义具体的方法路由。这可以与控制器的基础路由结合使用。
[RoutePrefix("api/Test")] public class ProductsController : ApiController { // GET api/Test [HttpGet] [Route("GetProducts")] public IHttpActionResult GetProducts() { return Ok("获取成功"); } // GET api/Test/5 [HttpGet] [Route("GetProduct")] [Route("{id:int}")] // 使用路由约束来确保id是整数 public IHttpActionResult GetProduct(int id) { return Ok($"{id}获取成功"); } // POST api/Test [HttpPost] [Route("CreateProduct")] public IHttpActionResult CreateProduct([FromBody] int id) { return Ok($"{id}创建成功"); } }
在上面的例子中,GetProducts
方法将响应 GET api/products
请求,GetProduct
方法将响应形如 GET api/products/5
的请求,而 CreateProduct
方法将响应 POST api/products
请求。
这些特性用于指定控制器方法应该响应哪种HTTP方法。例如,[HttpGet]
表示该方法应该响应GET请求,而 [HttpPost]
表示应该响应POST请求。
// 响应 GET 请求
[HttpGet]
public IHttpActionResult GetSomething()
{
// ...
}
// 响应 POST 请求
[HttpPost]
public IHttpActionResult PostSomething([FromBody]object value)
{
// ...
}
在 [Route]
特性中,可以使用路由约束来限制路由参数的格式或类型。例如,{id:int}
约束确保 id
参数是一个整数。
在 WebApiConfig
类的 Register
方法中,需要调用 config.MapHttpAttributeRoutes();
来启用特性路由。这样,Web API 框架就会查找并使用在控制器和方法上定义的路由特性。
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API 配置和服务
// 启用特性路由
config.MapHttpAttributeRoutes();
// 其他路由配置...
}
}
确保路由模板是唯一的,以避免路由冲突。如果两个不同的方法具有相同的路由模板和相同的HTTP方法,Web API 将无法确定哪个方法应该处理特定的请求,这会导致运行时错误。
通过不同的方式从HTTP请求中获取数据,包括查询字符串、表单数据、JSON数据等。以下是如何处理这些不同数据类型的示例:
查询字符串是附加在URL后面的键值对,通常以?
开头,并通过&
分隔多个键值对。
在Web API中,可以通过方法的参数来自动绑定查询字符串的值。ASP.NET Web API 支持简单的类型绑定,如int
、string
等,也支持复杂类型的绑定。
[HttpGet]
[Route("GetProduct")]
[Route("{id:int}")] // 使用路由约束来确保id是整数
public IHttpActionResult GetProduct(int id)
{
// id 将从查询字符串中获取,例如:GET api/test/GetProduct?id=9905
return Ok($"{id}创建成功");
}
如果需要获取多个查询字符串参数,可以简单地在方法签名中添加更多的参数。
对于POST请求中的表单数据,可以使用[FromBody]
特性来从请求正文中获取数据。这通常用于application/x-www-form-urlencoded
或multipart/form-data
类型的请求。
[HttpPost]
[Route("PostFormData")]
public IHttpActionResult PostFormData([FromBody] FormDataCollection formData)
{
// formData 将包含表单数据
string value = formData.Get("key");
return Ok(value);
}
对于简单类型的表单数据,也可以直接将它们作为参数:
public IHttpActionResult PostSimpleFormData([FromBody]string value)
{
// value 将直接从表单数据中获取
// ... 处理数据 ...
}
对于JSON数据,通常会创建一个与JSON结构相对应的C#类,并使用[FromBody]
特性来绑定请求正文中的JSON到该类的实例。
首先,定义一个与JSON数据匹配的C#类:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
然后,在API方法中,使用这个类作为参数类型,并使用[FromBody]
特性:
public IHttpActionResult PostProduct([FromBody]Product product)
{
// product 对象将从请求正文的JSON中自动填充
// ... 处理产品数据 ...
}
确保客户端发送的请求的Content-Type
头设置为application/json
,这样Web API才能正确解析JSON数据。
如果需要直接读取请求的原始内容,而不是将其绑定到某个对象,可以使用HttpRequestMessage
的Content
属性来读取流。
public async Task<IHttpActionResult> ReadRawRequestBody()
{
string content = await Request.Content.ReadAsStringAsync();
// content 现在包含请求的原始内容
// ... 处理原始内容 ...
}
在这个例子中,ReadAsStringAsync
方法用于异步读取请求体的内容作为一个字符串。注意,这通常在不需要将请求体绑定到某个对象时使用,因为它不提供类型安全或验证。
Content-Type
头与期望相匹配(例如,对于JSON数据,它应该是application/json
)。[FromBody]
特性时,Web API将尝试从请求正文中读取数据。一个方法通常只能有一个参数使用[FromBody]
,因为请求正文只能被读取一次。客户端可以通过使用HttpClient类请求接口获取响应数据,以下是一个典型示例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.Http; using Newtonsoft.Json; namespace ConsoleApp1 { internal class Program { static readonly HttpClient httpClient = new HttpClient(); static async Task Main(string[] args) { var getResponse = await httpClient.GetAsync("https://localhost:44352/api/Test/GetUser"); if (getResponse.IsSuccessStatusCode) { var content = await getResponse.Content.ReadAsStringAsync(); Console.WriteLine(content); // 输出响应内容,例如 ["value1","value2"] } else { Console.WriteLine($"Error: {getResponse.StatusCode}"); } //请求GetUser接口 User user = new User() { Id = 3, Name = "Charlie", Email = "charlie@example.com" }; string json=JsonConvert.SerializeObject(user); StringContent content1 = new StringContent(json, Encoding.UTF8, "application/json"); var getResponse1=await httpClient.PostAsync("https://localhost:44352/api/test/PostUser", content1 ); if (getResponse1.IsSuccessStatusCode) { var result= await getResponse1.Content.ReadAsStringAsync(); Console.WriteLine(result); } //请求PutUser接口 User user1 = new User() { Id = 10086, Name = "Charlie", Email = "charlie@example.com" }; string json1 = JsonConvert.SerializeObject(user1); StringContent content2 = new StringContent(json1, Encoding.UTF8, "application/json"); var getResponse2 = await httpClient.PutAsync("https://localhost:44352/api/test/PutUser?id=10086", content2); if (getResponse2.IsSuccessStatusCode) { var result2 = await getResponse2.Content.ReadAsStringAsync(); Console.WriteLine(result2); } Console.ReadKey(); } } public class User { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } } }
身份验证是确认用户身份的过程。Web API 通常使用令牌(如 JWT 令牌)或基于 Cookie 的身份验证机制。
JWT 是一种用于身份验证的开放标准(RFC 7519)。它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。这些信息可以被验证和信任,因为它们是数字签名的。
对于基于浏览器的应用,Web API 可以使用Cookie进行身份验证。用户登录时,服务器在响应中设置一个包含会话信息的Cookie。后续的请求会携带这个Cookie,服务器根据Cookie识别用户身份。
授权是确定用户是否有权访问特定资源的过程。这通常通过角色或声明来实现。
可以为用户分配角色(如“管理员”、“用户”等),并在Web API中定义哪些角色可以访问哪些资源。
[Authorize(Roles = "Admin")]
属性在控制器或操作方法上指定允许的角色。声明是关于用户、设备或其他实体的信息。它们可以是任何类型的数据,如用户的电子邮件地址、姓名或自定义属性。
# 五、身份验证和授权 ## 1、身份验证 身份验证是确认用户身份的过程。Web API 通常使用令牌(如 JWT 令牌)或基于 Cookie 的身份验证机制。 ### 1.1、 JWT(JSON Web Tokens)身份验证 JWT 是一种用于身份验证的开放标准(RFC 7519)。它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。这些信息可以被验证和信任,因为它们是数字签名的。 - 用户向认证服务器(如IdentityServer)发送凭据(用户名和密码)。 - 认证服务器验证凭据并返回一个JWT令牌。 - 客户端(如移动应用或Web前端)在后续的API请求中携带此令牌。 - Web API 验证令牌的签名,并确认其有效性。 ### 1.2、 基于Cookie的身份验证 对于基于浏览器的应用,Web API 可以使用Cookie进行身份验证。用户登录时,服务器在响应中设置一个包含会话信息的Cookie。后续的请求会携带这个Cookie,服务器根据Cookie识别用户身份。 ## 2、授权 授权是确定用户是否有权访问特定资源的过程。这通常通过角色或声明来实现。 ### 2.1、基于角色的授权 可以为用户分配角色(如“管理员”、“用户”等),并在Web API中定义哪些角色可以访问哪些资源。 - 使用`[Authorize(Roles = "Admin")]`属性在控制器或操作方法上指定允许的角色。 - 配置Web API以使用角色管理器来解析角色。 ### 2.2、基于声明的授权 声明是关于用户、设备或其他实体的信息。它们可以是任何类型的数据,如用户的电子邮件地址、姓名或自定义属性。 - 在用户登录时,将声明添加到身份验证令牌中。 - 在Web API中,使用`[Authorize(ClaimType = "email", ClaimValue = "user@example.com")]`来指定允许的声明。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。