mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-19 18:06:45 +08:00
297 lines
8.8 KiB
Plaintext
297 lines
8.8 KiB
Plaintext
---
|
||
id: httpservice
|
||
title: 创建HttpService
|
||
---
|
||
|
||
### 定义
|
||
|
||
命名空间:TouchSocket.Http <br/>
|
||
程序集:[TouchSocket.Http.dll](https://www.nuget.org/packages/TouchSocket.Http)
|
||
|
||
|
||
## 一、说明
|
||
|
||
**HttpService**是能够提供Http相关服务的基础类型。
|
||
|
||
## 二、产品特点
|
||
|
||
- 支持HTTPS。
|
||
- **多种数据接收模式**
|
||
- **多地址监听**(可以一次性监听多个IP及端口)
|
||
|
||
## 三、产品应用场景
|
||
|
||
- HTTP基础使用场景:可跨平台、跨语言使用。
|
||
|
||
|
||
## 四、服务器架构
|
||
|
||
服务器在收到新客户端连接时,会创建一个HttpSocketClient的派生类实例,与远程HttpClient对应,后续的数据通信均由此实例负责。
|
||
|
||
<img src={require('@site/static/img/docs/createhttpservice-1.png').default} width="500" />
|
||
|
||
|
||
## 五、支持插件接口
|
||
|
||
声明自定义实例类,然后实现**IHttpPlugin**接口,即可实现下列事务的触发。或者继承自**HttpPluginBase**类,重写相应方法即可。
|
||
|
||
| 插件方法| 功能 |
|
||
| --- | --- |
|
||
| IHttpPlugin | 当收到所有Http请求时。|
|
||
|
||
|
||
## 六、使用HttpService
|
||
|
||
HttpService的创建,基本和TcpService一致,也可以通过继承实现,下列仅演示最简单实现。
|
||
|
||
HttpService的相关事务,会通过**插件**触发。
|
||
|
||
### 6.1 创建HttpService
|
||
|
||
```csharp showLineNumbers
|
||
var service = new HttpService();
|
||
service.Setup(new TouchSocketConfig()//加载配置
|
||
.SetListenIPHosts(7789)
|
||
.ConfigureContainer(a =>
|
||
{
|
||
a.AddConsoleLogger();
|
||
})
|
||
.ConfigurePlugins(a =>
|
||
{
|
||
//以下即是插件
|
||
a.Add<MyHttpPlug1>();
|
||
a.Add<MyHttpPlug2>();
|
||
a.Add<MyHttpPlug3>();
|
||
a.Add<MyHttpPlug4>();
|
||
|
||
//default插件应该最后添加,其作用是
|
||
//1、为找不到的路由返回404
|
||
//2、处理header为Option的探视跨域请求。
|
||
a.UseDefaultHttpServicePlugin();
|
||
}));
|
||
|
||
service.Start();
|
||
```
|
||
|
||
:::tip 提示
|
||
|
||
DefaultHttpServicePlugin插件最好添加在插件中,如果没有添加的话,最好自己做好缺省路由和跨域配置。
|
||
|
||
:::
|
||
|
||
### 6.2 使用插件处理请求参数
|
||
|
||
#### 6.2.1 Query参数
|
||
|
||
```csharp showLineNumbers
|
||
string value = e.Context.Request.Query["key"];
|
||
```
|
||
|
||
#### 6.2.2 Header参数
|
||
|
||
```csharp showLineNumbers
|
||
string value = e.Context.Request.Headers["key"];
|
||
```
|
||
|
||
亦或者
|
||
|
||
```csharp showLineNumbers
|
||
string value = e.Context.Request.Headers[HttpHeaders.Cookie];
|
||
```
|
||
|
||
#### 6.2.3 Form参数
|
||
|
||
```csharp showLineNumbers
|
||
string value = e.Context.Request.Forms["key"];
|
||
```
|
||
|
||
### 6.3 使用插件处理请求
|
||
|
||
#### 6.3.1 Get请求
|
||
|
||
```csharp showLineNumbers
|
||
public class MyHttpPlug1 : PluginBase, IHttpPlugin<IHttpSocketClient>
|
||
{
|
||
public async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
|
||
{
|
||
if (e.Context.Request.IsGet())
|
||
{
|
||
if (e.Context.Request.UrlEquals("/success"))
|
||
{
|
||
//直接响应文字
|
||
e.Context.Response.FromText("Success").Answer();//直接回应
|
||
Console.WriteLine("处理完毕");
|
||
return;
|
||
}
|
||
}
|
||
|
||
//无法处理,调用下一个插件
|
||
await e.InvokeNext();
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 6.3.2 Get文件请求
|
||
|
||
```csharp showLineNumbers
|
||
public class MyHttpPlug2 : PluginBase, IHttpPlugin<IHttpSocketClient>
|
||
{
|
||
public async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
|
||
{
|
||
if (e.Context.Request.IsGet())
|
||
{
|
||
if (e.Context.Request.UrlEquals("/file"))
|
||
{
|
||
try
|
||
{
|
||
//直接回应文件。
|
||
e.Context.Response
|
||
.SetStatus()//必须要有状态
|
||
.FromFile(@"D:\System\Windows.iso", e.Context.Request);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
e.Context.Response.SetStatus(403)
|
||
.FromText(ex.Message)
|
||
.Answer();
|
||
}
|
||
|
||
return;
|
||
}
|
||
}
|
||
await e.InvokeNext();
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 6.3.3 Get页面请求
|
||
|
||
```csharp showLineNumbers
|
||
public class MyHttpPlug3 : PluginBase, IHttpPlugin<IHttpSocketClient>
|
||
{
|
||
public async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
|
||
{
|
||
if (e.Context.Request.IsGet())
|
||
{
|
||
if (e.Context.Request.UrlEquals("/html"))
|
||
{
|
||
//回应html
|
||
var stringBuilder = new StringBuilder();
|
||
stringBuilder.AppendLine("<!DOCTYPE html>");
|
||
stringBuilder.AppendLine("<html>");
|
||
stringBuilder.AppendLine("<head>");
|
||
stringBuilder.AppendLine("<meta charset=\"utf-8\"/>");
|
||
stringBuilder.AppendLine("<title>TouchSocket</title>");
|
||
stringBuilder.AppendLine("</head>");
|
||
stringBuilder.AppendLine("<body>");
|
||
stringBuilder.AppendLine("<div id=\"kuang\" style=\"width: 50%;height: 85%;left: 25%;top:15%;position: absolute;\">");
|
||
stringBuilder.AppendLine("<a id=\"MM\" style=\"font-size: 30px;font-family: 微软雅黑;width: 100%;\">王二麻子</a>");
|
||
stringBuilder.AppendLine("<input type=\"text\" id=\"NN\" value=\"\" style=\"font-size: 30px;width:100%;position: relative;top: 30px;\"/>");
|
||
stringBuilder.AppendLine("<input type=\"button\" id=\"XX\" value=\"我好\" style=\"font-size: 30px;width: 100%;position: relative;top: 60px;\" onclick=\"javascript:jump()\" />");
|
||
stringBuilder.AppendLine("</div>");
|
||
stringBuilder.AppendLine("</body>");
|
||
stringBuilder.AppendLine("</html>");
|
||
|
||
e.Context.Response
|
||
.SetStatus()//必须要有状态
|
||
.SetContentTypeByExtension(".html")
|
||
.SetContent(stringBuilder.ToString());
|
||
e.Context.Response.Answer();
|
||
return;
|
||
}
|
||
}
|
||
|
||
await e.InvokeNext();
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 6.3.4 Post文件请求
|
||
|
||
```csharp showLineNumbers
|
||
public class MyHttpPlug4 : PluginBase, IHttpPlugin<IHttpSocketClient>
|
||
{
|
||
public async Task OnHttpRequest(IHttpSocketClient client, HttpContextEventArgs e)
|
||
{
|
||
if (e.Context.Request.IsPost())
|
||
{
|
||
if (e.Context.Request.UrlEquals("/uploadfile"))
|
||
{
|
||
try
|
||
{
|
||
if (e.Context.Request.TryGetContent(out var bodys))//一次性获取请求体
|
||
{
|
||
return;
|
||
}
|
||
|
||
while (true)//当数据太大时,可持续读取
|
||
{
|
||
var buffer = new byte[1024 * 64];
|
||
var r = e.Context.Request.Read(buffer, 0, buffer.Length);
|
||
if (r == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
//这里可以一直处理读到的数据。
|
||
}
|
||
|
||
//下面逻辑是接收小文件。
|
||
|
||
if (e.Context.Request.ContentLength > 1024 * 1024 * 100)//全部数据体超过100Mb则直接拒绝接收。
|
||
{
|
||
e.Context.Response
|
||
.SetStatus(403, "数据过大")
|
||
.Answer();
|
||
return;
|
||
}
|
||
|
||
//此操作会先接收全部数据,然后再分割数据。
|
||
//所以上传文件不宜过大,不然会内存溢出。
|
||
var multifileCollection = e.Context.Request.GetMultifileCollection();
|
||
|
||
foreach (var item in multifileCollection)
|
||
{
|
||
var stringBuilder = new StringBuilder();
|
||
stringBuilder.Append($"文件名={item.FileName}\t");
|
||
stringBuilder.Append($"数据长度={item.Length}");
|
||
client.Logger.Info(stringBuilder.ToString());
|
||
}
|
||
|
||
e.Context.Response
|
||
.SetStatus()
|
||
.FromText("Ok")
|
||
.Answer();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
client.Logger.Exception(ex);
|
||
}
|
||
}
|
||
}
|
||
await e.InvokeNext();
|
||
}
|
||
}
|
||
```
|
||
|
||
:::tip 提示
|
||
|
||
该操作支持大型文件,也支持断点续传、支持迅雷加速等。
|
||
|
||
:::
|
||
|
||
|
||
## 七、创建加密Ssl的HttpsService
|
||
|
||
Https服务器,和http服务器几乎一样,只不过增加了一个Ssl的配置。
|
||
|
||
```csharp showLineNumbers
|
||
.SetServiceSslOption(new ServiceSslOption()
|
||
{
|
||
Certificate = new X509Certificate2("Socket.pfx", "Socket"),
|
||
SslProtocols = SslProtocols.Tls12
|
||
})
|
||
```
|
||
|
||
|
||
[本文示例Demo](https://gitee.com/RRQM_Home/TouchSocket/tree/master/examples/Http) |