1.Http请求的概念
HTTP 请求是客户端向服务器发送的请求,用于获取特定资源或执行特定操作。它包含请求行、请求头部和请求体等部分,其中请求行包含请求的方法、URL 和协议版本,请求头部包含关于客户端请求的各种信息,请求体则包含需要传输给服务器的数据。
2.Http请求API的介绍
- HttpListener
HttpListener 是 .NET Framework 提供的用于创建 HTTP 服务器以侦听传入 HTTP请求的类。
用法:
HttpListener httpListener;
httpListener = new HttpListener();
- HttpClient
HttpClient 是 .NET Framework 提供的用于发送 HTTP 请求的类。它可以用于向服务器发送 GET、POST
等类型的请求,并处理服务器的响应。
用法:
HttpClient httpClient;
httpClient = new HttpClient();
- httpListener.GetContextAsync
httpListener.GetContextAsync用于异步地获取传入的 HTTP 请求并返回一个HttpListenerContext 对象,在 HTTP 服务器中等待并处理客户端发送的请求。
用法:
var context = await httpListener.GetContextAsync();
- HttpListenerContext
HttpListenerContext 类表示了收到的 HTTP 请求以及将要发送的 HTTP 响应。它是 HttpListener类的一部分,用于处理传入的 HTTP 请求并生成相应的响应。
用法:
HttpListenerContext context = awaithttpListener.GetContextAsync();
HttpListenerContext 的一些主要属性和方法:
Request:表示收到的 HTTP 请求。通过该属性,你可以获取请求的各种信息,如请求头、请求方法、请求体等。
Response:表示将要发送的 HTTP 响应。通过该属性,你可以设置要发送的响应的各种信息,如响应头、响应状态码、响应体等。
User:表示与请求关联的用户身份信息。可以使用该属性来获取关于用户的信息,如用户名、权限等。
ErrorStatus:表示在处理请求时发生的错误状态。如果请求处理过程中出现了错误,可以使用该属性来获取错误状态码和错误信息。
Abort():用于取消请求并关闭连接。如果在处理请求过程中发现无法继续处理或需要提前结束请求,可以调用该方法来取消请求并关闭连接。
- context.Request.RawUrl
context.Request.RawUrl 是 HttpListenerRequest 对象的一个属性,用于获取客户端发送的原始 URL地址,不经过任何解析或编码。
用法:
var text = context.Request.RawUrl;
- HttpListenerContext.Response
HttpListenerContext.Response 属性表示将要发送的 HTTP
响应。通过该属性,你可以设置要发送的响应的各种信息,如响应头、响应状态码、响应体等
- stream.WriteAsync()
stream.WriteAsync() 方法能将数据写入到输出流中,从而将数据发送给客户端。
用法:
await stream.WriteAsync(data, 0, data.Length);//将data数组写入stream响应的输出流中
- httpListener.GetContextAsync
在 .NET 中,HttpListener 类用于创建一个 HTTP 服务器,可以监听指定的 URL 地址,并处理客户端发送的 HTTP
请求。
- context.Request.inputStream
context.Request.InputStream 提供了一个流对象,通过它可以读取客户端发送的请求主体数据。
用法:
Stream inpuStream = context.Request.InputStream;
- inputStream.ReadAsync
InputStream.ReadAsync 是用于异步读取请求主体数据的方法,它返回一个表示异步读取操作的任务。
用法:
Stream inpuStream = context.Request.InputStream;
int length = await inpuStream.ReadAsync(readData, 0, readData.Length);
- HttpListenerContext.Response
HttpListenerContext.Response 表示用于向客户端发送响应的对象。通过 Response
属性,你可以设置响应的状态码、响应头以及响应主体内容等信息。
- stream.WriteAsync
stream.WriteAsync
是一个用于异步写入数据到流的方法。在C#中,流(Stream)是一种用于读取或写入序列数据的抽象概念。WriteAsync
方法允许你以异步的方式将数据写入到流中,而不会阻塞当前线程。
用法:
Stream stream = context.Response.OutputStream;
await stream.WriteAsync(data, 0, data.Length);
- stream.close()
这个方法是用来关闭流的
用法:
var stream = context.Response.OutputStream;
stream.close()
- HttpClient.GetAsync
HttpClient 类提供了发送 HTTP GET 请求的功能,GetAsync 方法允许你以异步的方式发送 GET 请求,并返回一个表示异步操作的 Task 对象,其中包含了表示请求响应的信息。
用法:
HttpResponseMessage response = await httpClient.GetAsync(page);
- HttpResponseMessage
HttpResponseMessage 类表示 HTTP 响应消息。当你发送 HTTP 请求并收到响应时,服务器将返回一个 HttpResponseMessage 对象,其中包含了响应的状态码、头部信息和内容。你可以从中提取出响应的内容,并进行相应的处理。
用法:
string page = “http://127.0.0.1:8080/” + data;
HttpResponseMessage response = await httpClient.GetAsync(page);
- response.Content.ReadAsStringAsync()
这个方法是用来异步读取响应内容的,response 是一个 HttpResponseMessage 对象,它包含了服务器响应的相关信息。
用法:
string text = await response.Content.ReadAsStringAsync();
- HttpClient.PostAsync
PostAsync 方法用于以异步方式发送 HTTP POST 请求。你可以使用它来向服务器提交数据,通常用于提交表单数据或上传文件等操作。PostAsync 方法也返回一个表示异步操作的 Task 对象,你可以等待操作完成后处理响应。
用法:
string page = “http://127.0.0.1:8080/” + data;
StringContent stringContent = new StringContent(data);
var response = await httpClient.PostAsync(page, stringContent);
3.文件下载
1.客户端编写
if(data == "download")
{
//下载文件 不同的处理
//读取到的文件的数据
byte[] fileData = await response.Content.ReadAsByteArrayAsync();
string path = @"D:\Unity 2023.1.20f1c1\NetProject\DownLoad\unity.png";//路径要存在
FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate);
await fileStream.WriteAsync(fileData, 0, fileData.Length);
Debug.Log("下载完毕了");
}
else
{
string str = await response.Content.ReadAsStringAsync();
//使用 response.Content.ReadAsStringAsync() 方法读取 HTTP 响应的内容,并将其作为字符串返回
Debug.Log($"post response:{str}");
}
2.服务端编写
if (text.Contains("/login")){
byte[] data = Encoding.UTF8.GetBytes("登录成功");
await stream.WriteAsync(data, 0, data.Length);//将data数组写入stream响应的输出流中
stream.Close();
}
else if (text.Contains("/download"))
{
//1.获取到路径下的文件 byte[]
//2.将它读取后,响应给客户端
//3.客户端拿到之后-》写到本地就可以了
string path = @"D:\Unity 2023.1.20f1c1\NetProject\DB\unity.png";
FileStream file = new FileStream(path, FileMode.Open);
//创建一个文件流对象 file,用于读取文件中的数据
byte[] data = new byte[file.Length];
//创建一个大小为文件长度的字节数组 data
int fileLength = await file.ReadAsync(data, 0,data.Length);
//使用文件流的 ReadAsync() 方法异步从文件中读取数据
//并将读取的数据存储到 data 数组
Console.WriteLine("文件大小:" + fileLength);
await stream.WriteAsync(data, 0, data.Length);
//使用网络流 stream 的 WriteAsync() 方法异步将读取的文件数据写入到客户端
stream.Close();
}
4.总体客户端编写
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using UnityEngine;
public class Client_Http : MonoBehaviour
{
HttpClient httpClient;
// Start is called before the first frame update
void Start()
{
httpClient = new HttpClient();
//Connect();
}
//public void Connect()
//{
// throw new NotImplementedException();
//}
public async void Get(string data)
{
string page = "http://127.0.0.1:8080/" + data;
HttpResponseMessage response = await httpClient.GetAsync(page);
//发送 GET 请求到指定的 URL,并等待服务器的响应
Debug.Log("http get:" + data);
string text = await response.Content.ReadAsStringAsync();
//将 HTTP 响应的内容异步读取为字符串
Debug.Log("http get. 返回的数据是:"+ text);
}
public async void Post(string data)
{
string page = "http://127.0.0.1:8080/" + data;
StringContent stringContent = new StringContent(data);
//将指定的字符串数据包装成 HTTP 请求的内容
Dictionary<string,string> dct = new Dictionary<string,string>();
dct["account"] = "xxx";
dct["pwd"] = data;//“account” 键和 “pwd” 键分别赋予了值 “xxx” 和 data
FormUrlEncodedContent content = new FormUrlEncodedContent(dct);
//创建 HTTP 请求的内容对象 content
//FormUrlEncodedContent类会将字典中的键值对数据编码为URL编码形式
//以便将其作为 HTTP 请求的内容发送给服务器。
var response = await httpClient.PostAsync(page, stringContent);
if(data == "download")
{
//下载文件 不同的处理
//读取到的文件的数据
byte[] fileData = await response.Content.ReadAsByteArrayAsync();
string path = @"D:\Unity 2023.1.20f1c1\NetProject\DownLoad\unity.png";
FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate);
await fileStream.WriteAsync(fileData, 0, fileData.Length);
Debug.Log("下载完毕了");
}
else
{
string str = await response.Content.ReadAsStringAsync();
//使用 response.Content.ReadAsStringAsync() 方法读取 HTTP 响应的内容,并将其作为字符串返回
Debug.Log($"post response:{str}");
}
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
Get("login");
}
if (Input.GetKeyDown(KeyCode.S))
{
//Post("login");
Post("download");
}
}
}
5.总体服务端编写
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Server.Net
{
internal class HttpServer
{
string page = "http://127.0.0.1:8080/";
HttpListener httpListener;
public void Start()
{
httpListener = new HttpListener();
httpListener.Prefixes.Add(page);
httpListener.Start();
Accept();
Console.WriteLine("http Server Start");
HandleGet();
HandlePost();
}
//处理Get请求
public async void HandleGet()
{
var context = await httpListener.GetContextAsync();
//监听 HTTP 请求
var text = context.Request.RawUrl;
//获取 HTTP 请求的原始 URL
//可以获取到客户端发送的请求的详细信息,包括路径和查询参数等内容
Console.WriteLine(text);
var stream = context.Response.OutputStream;
//表示响应的输出流,可以用于向客户端发送响应数据
if (text.Contains("/login")){
byte[] data = Encoding.UTF8.GetBytes("登录成功");
await stream.WriteAsync(data, 0, data.Length);//将data数组写入stream响应的输出流中
stream.Close();
}
else if (text.Contains("/download"))
{
//1.获取到路径下的文件 byte[]
//2.将它读取后,响应给客户端
//3.客户端拿到之后-》写到本地就可以了
string path = @"D:\Unity 2023.1.20f1c1\NetProject\DB\unity.png";
FileStream file = new FileStream(path, FileMode.Open);
//创建一个文件流对象 file,用于读取文件中的数据
byte[] data = new byte[file.Length];
//创建一个大小为文件长度的字节数组 data
int fileLength = await file.ReadAsync(data, 0,data.Length);
//使用文件流的 ReadAsync() 方法异步从文件中读取数据
//并将读取的数据存储到 data 数组
Console.WriteLine("文件大小:" + fileLength);
await stream.WriteAsync(data, 0, data.Length);
//使用网络流 stream 的 WriteAsync() 方法异步将读取的文件数据写入到客户端
stream.Close();
}
HandleGet();
HandlePost();
}
public async void HandlePost()
{
HttpListenerContext context = await httpListener.GetContextAsync();监听 HTTP 请求
Stream inpuStream = context.Request.InputStream;//表示请求的输入流,读取客户端发送的请求数据
byte[] readData = new byte[context.Request.ContentLength64];
//获取请求的正文长度,知道读取多少字节的数据
//能创建一个对应长度的字节数组 readData
//用于存储从请求输入流中读取的数据。
int length = await inpuStream.ReadAsync(readData, 0, readData.Length);
//异步读取请求的输入流,并将数据存储到 readData 字节数组中
inpuStream.Close();
string text = Encoding.UTF8.GetString(readData);
Console.WriteLine("请求的内容:" + text);
Stream stream = context.Response.OutputStream;
if(text.Contains("login"))
{
Console.WriteLine("收到客户端的登录请求");
byte[] data = Encoding.UTF8.GetBytes("登录成功");
await stream.WriteAsync(data, 0, data.Length);
stream.Close();
}
}
//处理Post请求
public void Accept()
{
}
}
}
注意,前面关于Http请求API的介绍,不懂得可以看最后两个总体的客户端编写和服务端总体编写!!!