当前位置:   article > 正文

接口开发笔记-WebApi

webapi

一、基础概念与原理

1、WebAPI的基本概念。

WebAPI是一种基于HTTP协议的网络应用程序接口,它使用JSON或XML格式来传输数据。WebAPI是服务器端应用程序,允许客户端应用程序通过HTTP请求来访问服务器上的数据。WebAPI支持RESTful服务,是构建这种服务的理想选择。同时,WebAPI的客户端系统和服务系统彼此独立,调用者可以使用不同的语言(如Java、Python、Ruby等)进行API的调用。

2、与WebService、WCF等技术的区别与联系。

2.1、WebAPI与WebService的区别

  1. 数据传输格式:虽然WebService也支持基于XML格式的数据传输,但在实际生产过程中,WebAPI更常见的数据类型格式是JSON。与XML相比,JSON更加轻量,序列化和反序列化的工作量更少,因此在解析速率方面更快,对带宽的要求更低。
  2. 交互方式:WebService基于SOAP协议,而WebAPI使用json数据来传递信息,更加轻量化地构建HTTP服务框架。
  3. 系统交互:WebService通常仅在两个系统之间交互,并且不同的客户端下各浏览器对XML的解析方式不一致,需要重复编写很多代码。而WebAPI的客户端系统和服务系统彼此独立,具有更广泛的适用性。

2.2、WebAPI与WCF的区别

  1. 框架与开放性:WCF是附带.NET框架的,不是开源的;而WebAPI是开源的,并且也附带.NET框架。
  2. 服务支持:WCF提供对有限RESTFUL服务的支持;而WebAPI是构建RESTFUL服务的理想选择。
  3. 配置方式:WCF使用web.config和属性来配置一个HttpConfiguration类;而WebAPI则主要使用web.config服务进行配置。
  4. 编程模型:WCF依赖于基于属性的编程模型;而WebAPI将HTTP动词映射到方法。
  5. 功能支持:WCF不支持MVC功能,如控制器、路由、过滤器等;而WebAPI则与这些功能紧密集成。

3、如何通过WebAPI实现资源的操作。

通过ASP.NET Web API框架,可以实现资源的创建(POST)、读取(GET)、更新(PUT/PATCH)和删除(DELETE)等操作,这些操作都遵循RESTful架构风格。以下是一个简单的步骤:

1.1、创建ASP.NET Web API项目

首先,需要在Visual Studio中创建一个ASP.NET Web API项目。通过选择“文件” -> “新建” -> “项目”,然后在项目模板中选择“ASP.NET Web 应用程序”来完成。在创建过程中,选择“Web API”作为项目类型。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.2、定义模型(Model)

模型类代表了你想要通过API操作的数据资源。例如,如果你想要操作一个用户资源,你可以定义一个User类:

public class User  
{  
    public int Id { get; set; }  
    public string Name { get; set; }  
    public string Email { get; set; }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

1.3、创建控制器(Controller)

控制器负责处理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();
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119

1.4、配置路由(Routing)

在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 }  
        );  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

1.5、运行和测试API

运行Web API项目,并使用工具如Postman或浏览器来测试你的API。你可以发送GET、POST、PUT和DELETE请求到相应的URL,并观察响应。

例如,要获取所有用户,你可以发送一个GET请求到http://localhost:<port>/api/Test/GetUser。要创建一个新用户,你可以发送一个POST请求到http://localhost:<port>/api/Test/PostUser,并在请求体中包含用户数据。

1.6、异常处理和验证

使用ASP.NET Web API时,可以通过模型验证、异常过滤器以及其他机制来增强API的健壮性和安全性。

1.6.1 模型验证

对于PostUserPutUser方法,可以使用数据注解(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; }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在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("用户更新成功");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
1.6.2 异常过滤器

创建自定义的异常过滤器来处理未捕获的异常,并返回适当的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);  
    }  
} 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

然后,我们可以在控制器或全局范围内应用这个过滤器:

[HttpExceptionFilter]  
public class TestController : ApiController  
{  
    // ... 方法 ...  
}
  • 1
  • 2
  • 3
  • 4
  • 5

或者,在Web API配置中全局注册:

public static class WebApiConfig  
{  
    public static void Register(HttpConfiguration config)  
    {  
        // ... 其他配置 ...  
          
        config.Filters.Add(new HttpExceptionFilterAttribute());  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
1.6.3 身份验证和授权

对于安全性,需要实施身份验证和授权机制。ASP.NET Web API支持多种身份验证方式,如OAuth 2.0、JWT等。可以使用内置的[Authorize]属性来要求用户授权才能访问某些API。

1.6.4 跨站请求伪造(CSRF)防护

为了防止跨站请求伪造攻击,应该考虑在API中实施防护措施,比如检查请求的来源或使用验证令牌。

1.6.5 输入验证和清理

对于所有从客户端接收的输入,都应该进行验证和清理,以防止SQL注入、跨站脚本(XSS)等攻击。可以使用ASP.NET中的安全功能,比如编码助手类,来清理和编码输出。

1.6.6 响应格式化

返回具体的错误信息或详细的堆栈跟踪可能会泄露敏感信息。在生产环境中,应只返回一般性的错误消息,并避免暴露内部实现细节。

1.6.7 日志记录

实现良好的日志记录机制可以帮助你追踪问题、识别攻击和审计API的使用情况。可以使用ASP.NET的日志记录功能或第三方日志库。

1.7、部署API

完成开发和测试后,需要将Web API项目部署到IIS服务器或其他托管环境中,以便其他客户端应用程序可以访问它。

4、HTTP协议及其在WebAPI中的应用。

在前一篇中已经专门讲过HTTP协议,在此不多做赘述。

接口开发笔记-HTTP协议

二、项目创建与配置

1、创建WebAPI项目,包括项目的基本结构和文件组成。

创建项目前面已经说过了,现在主要记录项目的基本结构和文件组成

1.1、项目结构

  • 项目根目录:包含项目的所有文件和文件夹。
  • Controllers:存放Web API控制器的文件夹。控制器是处理HTTP请求的主要类。
  • App_Start:包含Web API的配置文件,如WebApiConfig.cs
  • Models:存放数据模型的文件夹(可选)。
  • Views:对于Web API项目,这个文件夹通常是空的,因为API不返回视图。
  • Properties:包含项目属性的文件夹,如AssemblyInfo.cslaunchSettings.json(对于ASP.NET Core项目)。
  • 其他文件和文件夹:根据我们的项目设置和所选模板,可能还有其他文件和文件夹,如wwwroot(用于存放静态文件)或Dependencies(包含项目依赖项)。

1.2、文件组成

  • Global.asaxStartup.cs:项目的入口点。对于ASP.NET,Global.asax包含应用程序的启动和关闭事件。对于ASP.NET Core,Startup.cs类中的ConfigureServicesConfigure方法用于配置服务和请求处理管道。
  • WebApiConfig.cs:Web API的配置文件,用于定义路由和其他设置。
  • 控制器文件(如ValuesController.cs):控制器类,用于处理特定的HTTP请求。每个控制器通常对应一组相关的API端点。
  • 模型类文件(可选):定义数据的模型或实体类。
  • 其他配置文件:如appsettings.json(用于存储应用程序设置)和web.config(用于IIS设置)。

2、Global.asax文件的配置及配置路由规则。

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);
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

在这个例子中,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 }  
            );  
        }  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

在这个 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" };
        } 
  
        // 其他动作方法...  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3、跨域配置、CORS(跨源资源共享)的原理及应用。

跨域资源共享(CORS,Cross-Origin Resource Sharing)是一个重要概念,它允许Web应用程序从不同的源(域、协议或端口)访问资源。默认情况下,出于安全考虑,浏览器会限制从一个源加载的文档或脚本与另一个源的资源进行交互。但是,通过CORS,服务器可以明确指定哪些外部源有权访问其资源。

3.1、CORS的原理

CORS是一个W3C规范,它定义了一种浏览器和服务器交互的方式来确定是否允许跨源请求。这主要通过服务器返回的HTTP响应头来实现。当浏览器发送一个跨域请求时,它会在请求头中包含Origin字段,表示请求的源。服务器根据这个Origin字段以及其他的CORS相关头信息(如Access-Control-Allow-Origin),来决定是否允许这个请求。

3.2、在C# WebAPI (.NET Framework) 中应用CORS

在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策略  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

请注意,使用"*"作为源、方法和头信息是一种非常宽松的策略,可能带来安全风险。在实际应用中,应该根据具体需求来限制这些值。

3.2.3 使用控制器或动作级别的CORS策略

除了全局策略外,还可以在控制器或动作级别上设置CORS策略。这可以通过在控制器或动作方法上使用[EnableCors]特性来实现。例如:

[EnableCors(origins: "http://example.com", headers: "*", methods: "*")]  
public class MyApiController : ApiController  
{  
    // ... 控制器方法 ...  
}
  • 1
  • 2
  • 3
  • 4
  • 5

或者,只在特定的动作方法上应用CORS策略:

public class MyApiController : ApiController  
{  
    [EnableCors(origins: "http://example.com", headers: "*", methods: "GET,POST")]  
    public IHttpActionResult MyAction()  
    {  
        // ... 动作方法实现 ...  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

安全注意事项

在配置CORS时,务必注意安全性。不要随意允许所有源、方法和头信息,因为这可能使你的API暴露给潜在的攻击者。应该根据API的实际需求和安全策略来仔细设置CORS策略。

此外,即使启用了CORS,仍然需要确保API的其他安全措施(如身份验证、授权和输入验证)得到妥善实施,以防止未授权访问和数据泄露。

三、控制器与路由

使用路由属性(如 [Route][HttpGet][HttpPost] 等)是定义和映射HTTP请求到特定控制器方法的一种非常方便的方式。这些特性允许你以声明式的方式指定如何路由到你的API方法,而不是依赖于全局路由配置。

下面是如何在WebAPI中使用这些路由属性的示例:

1、使用 [Route] 特性定义控制器的基础路由

在控制器类上使用 [Route] 特性,你可以定义一个基础路由前缀,该前缀将应用于控制器中的所有方法。

[RoutePrefix("api/Test")] 
public class TestController : ApiController  
{  
    // 控制器方法将映射到以 "api/Test" 为前缀的路由  
}
  • 1
  • 2
  • 3
  • 4
  • 5

2、使用 [Route] 特性定义方法级别的路由

在控制器的方法上使用 [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}创建成功");
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

在上面的例子中,GetProducts 方法将响应 GET api/products 请求,GetProduct 方法将响应形如 GET api/products/5 的请求,而 CreateProduct 方法将响应 POST api/products 请求。

3、使用 [HttpGet]、[HttpPost] 等特性指定HTTP方法

这些特性用于指定控制器方法应该响应哪种HTTP方法。例如,[HttpGet] 表示该方法应该响应GET请求,而 [HttpPost] 表示应该响应POST请求。

// 响应 GET 请求  
[HttpGet]  
public IHttpActionResult GetSomething()  
{  
    // ...  
}  
  
// 响应 POST 请求  
[HttpPost]  
public IHttpActionResult PostSomething([FromBody]object value)  
{  
    // ...  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4、路由约束

[Route] 特性中,可以使用路由约束来限制路由参数的格式或类型。例如,{id:int} 约束确保 id 参数是一个整数。

5、全局配置与特性路由的结合

WebApiConfig 类的 Register 方法中,需要调用 config.MapHttpAttributeRoutes(); 来启用特性路由。这样,Web API 框架就会查找并使用在控制器和方法上定义的路由特性。

public static class WebApiConfig  
{  
    public static void Register(HttpConfiguration config)  
    {  
        // Web API 配置和服务  
  
        // 启用特性路由  
        config.MapHttpAttributeRoutes();  
  
        // 其他路由配置...  
    }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

6、处理路由冲突

确保路由模板是唯一的,以避免路由冲突。如果两个不同的方法具有相同的路由模板和相同的HTTP方法,Web API 将无法确定哪个方法应该处理特定的请求,这会导致运行时错误。

四、数据处理与响应

1、如何从请求中获取数据

通过不同的方式从HTTP请求中获取数据,包括查询字符串、表单数据、JSON数据等。以下是如何处理这些不同数据类型的示例:

1.1、查询字符串(Query String)

查询字符串是附加在URL后面的键值对,通常以?开头,并通过&分隔多个键值对。

在Web API中,可以通过方法的参数来自动绑定查询字符串的值。ASP.NET Web API 支持简单的类型绑定,如intstring等,也支持复杂类型的绑定。

[HttpGet]
[Route("GetProduct")]
[Route("{id:int}")] // 使用路由约束来确保id是整数  
public IHttpActionResult GetProduct(int id)
{
    // id 将从查询字符串中获取,例如:GET api/test/GetProduct?id=9905  
    return Ok($"{id}创建成功");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果需要获取多个查询字符串参数,可以简单地在方法签名中添加更多的参数。

1.2、表单数据(Form Data)

对于POST请求中的表单数据,可以使用[FromBody]特性来从请求正文中获取数据。这通常用于application/x-www-form-urlencodedmultipart/form-data类型的请求。

[HttpPost]
[Route("PostFormData")]
public IHttpActionResult PostFormData([FromBody] FormDataCollection formData)
{
    // formData 将包含表单数据  
    string value = formData.Get("key");
    return Ok(value);  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

对于简单类型的表单数据,也可以直接将它们作为参数:

public IHttpActionResult PostSimpleFormData([FromBody]string value)  
{  
    // value 将直接从表单数据中获取  
    // ... 处理数据 ...  
}
  • 1
  • 2
  • 3
  • 4
  • 5

1.3、JSON数据

对于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; }  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后,在API方法中,使用这个类作为参数类型,并使用[FromBody]特性:

public IHttpActionResult PostProduct([FromBody]Product product)  
{  
    // product 对象将从请求正文的JSON中自动填充  
    // ... 处理产品数据 ...  
}
  • 1
  • 2
  • 3
  • 4
  • 5

确保客户端发送的请求的Content-Type头设置为application/json,这样Web API才能正确解析JSON数据。

1.4、读取原始请求体

如果需要直接读取请求的原始内容,而不是将其绑定到某个对象,可以使用HttpRequestMessageContent属性来读取流。

public async Task<IHttpActionResult> ReadRawRequestBody()  
{  
    string content = await Request.Content.ReadAsStringAsync();  
    // content 现在包含请求的原始内容  
    // ... 处理原始内容 ...  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这个例子中,ReadAsStringAsync方法用于异步读取请求体的内容作为一个字符串。注意,这通常在不需要将请求体绑定到某个对象时使用,因为它不提供类型安全或验证。

1.5、注意事项

  • 确保客户端发送的请求的Content-Type头与期望相匹配(例如,对于JSON数据,它应该是application/json)。
  • 当使用[FromBody]特性时,Web API将尝试从请求正文中读取数据。一个方法通常只能有一个参数使用[FromBody],因为请求正文只能被读取一次。
  • 对于复杂的请求类型(如自定义的媒体类型),可能需要编写自定义的模型绑定器或格式化程序来处理数据绑定。

2、客户端如何请求接口获取数据

客户端可以通过使用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; }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

五、身份验证和授权

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、基于声明的授权

声明是关于用户、设备或其他实体的信息。它们可以是任何类型的数据,如用户的电子邮件地址、姓名或自定义属性。

  • 在用户登录时,将声明添加到身份验证令牌中。
    get; set; }
    }
    }

# 五、身份验证和授权

## 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")]`来指定允许的声明。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/935792
推荐阅读
相关标签
  

闽ICP备14008679号