1.Unity的UnityWebRequest类
UnityWebRequest 提供了一个模块化系统,用于构成 HTTP 请求和处理 HTTP 响应。UnityWebRequest 系统的主要目标是让 Unity 游戏与 Web 浏览器后端进行交互。
1.HTTP 事务分解为三个不同的操作:
- 向服务器提供数据
- 从服务器接收数据
- HTTP 流量控制(例如,重定向和错误处理)
2.可以管理下列对象:
-
UploadHandler
对象处理数据到服务器的传输 -
DownloadHandler
对象处理从服务器接收的数据的接收、缓冲和后处理 -
UnityWebRequest
对象管理其他两个对象,还处理 HTTP 流量控制。此对象是定义自定义标头和 URL 的位置,也是存储错误和重定向信息的位置。
3.一次HTTP 事务的流程如下:
- 创建 Web 请求对象
- 配置 Web 请求对象
- 设置自定义标头
- 设置 HTTP 动词(例如 GET、POST 和 HEAD - 除 Android 之外的所有平台都允许使用自定义动词)
- 设置 URL *(可选)创建上传处理程序并将其附加到 Web 请求
- 提供要上传的数据
- 提供要上传的 HTTP 表单 *(可选)创建下载处理程序并将其附加到 Web 请求
- 发送 Web 请求
- 如果在协程中,可获得
Send()
调用的结果以等待请求完成 (可选)读取从下载处理程序接收的数据 (可选)从 UnityWebRequest 对象中读取错误信息、HTTP 状态码和响应标头
4.一次请求报文格式如下:
5.返回状态码
通过www.responseCode,可以获取返回状态码:
200表示正常
404大部分就是url写错了
500就大部分是服务器程序出错了
2.Unity客户端的代码实现:
1.登录功能实现(GET请求)
public string url_base = "http://127.0.0.1:5566";
public void Login(string username, string pwd)
{
StartCoroutine(login(username, pwd));
}
// 登录:"http://127.0.0.1:5566/login/?username=qwer&pwd=qwert"
IEnumerator login(string username, string password)
{
string url = url_base + "/login/?username=" + username + "&pwd=" + password;
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.SendWebRequest(); // 等待成功发送请求
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
Debug.Log(www.downloadHandler.text); // 返回结果
}
}
2.发送数据功能实现(POST请求)
这里定义了数据库中每个表的类型,只要创建一个对象,就可以发送到服务器中
[Serializable]
public class Insert<T>
{
public string tablename;
public T datarow;// 需要插入的数据,只有一行
}
// 数据库中的一个表的类型
[Serializable]
public class users
{
public int id = 0;
public string name = "";
public int age = 0;
public users() { }
public users(int i, string n, int a)
{
id = i;
name = n;
age = a;
}
}
还需要进行字符串到字节的转换,这里记录一下不同字符类型的区别:
ASCII 0-255 1个字节,不包括中文
Unicode(万国码) 定义了字符的编码值(包括中文),但是不定义存储方式(几进制)【比如一个字母1个字节就行,但是中文又可能需要4个字节】
UTF-8 定义存储Unicode存储方式,是一种可变长度的方案,可使用1~6个字节存储。
UTF-16:介于 UTF-8 和 UTF-32 的方案,采用2字节或者4字节进行存储
UTF-32:一种固定的4个字节的存储方式,编码一一对应即可,简单但是存储效率太低
json:其实就是字符串,但是是键值对的形式
//字符串格式转换为字节
public static byte[] StringToBytes(string StringMessage)
{
//字符串转UTF-8 byte
//string StringMessage = "Hello World How Are you? Pi /u03C0 Yen /uFFE5";
System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
return UTF8.GetBytes(StringMessage);
}
3.实现建立请求和数据发送:
public string url_base = "http://127.0.0.1:5566";
public void InsertData<T>(Insert<T> se)
{
StartCoroutine(Send_data<T>(se));
}
// 数据发送(表名、数据一行)
IEnumerator Send_data<T>(Insert<T> Send)
{
string url = url_base + "/insert/";
// 发送内容
/*
* {
* "tablename":"users",
* "datarow":{"id":60,"name":"test","age":123} //每个类不一样
* }
*/
string json_str = JsonUtility.ToJson(Send); // 转换成json格式
byte[] byte_data = StringToBytes(json_str);// 转换成字节流形式
print("发送" + json_str);
// 通过上传handler发送字节数据
UnityWebRequest www = new UnityWebRequest(url, "POST");
www.uploadHandler = (UploadHandler)new UploadHandlerRaw(byte_data); // 上传数据
www.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); // 接收数据
www.SetRequestHeader("Content-Type", "application/json"); //请求头 "application/x-www-form-urlencoded"
print("数据请求状态码:" + www.responseCode);
yield return www.SendWebRequest();
if (www.isHttpError || www.isNetworkError)
{
Debug.LogError(www.error);
}
else
{
Debug.Log("data upload compelete:");
Debug.Log(www.downloadHandler.text);
}
}
3.服务器代码的实现:
from flask import Flask,request,jsonify,make_response,json,redirect
from flask import request
app = Flask(__name__)
@app.route('/login/', methods=["GET"])
def login():
username = request.args.get('username')
pwd = request.args.get('pwd')
print("type:"+usertype)
# 接收处理
if username=='test' and pwd=='XXX'
return "Success"
return "Fail"
@app.route('/insert/',methods=['POST'])
def insert_data():
print("插入,接收数据:",request.data)
str_req = request.get_data(as_text=True)
dic_data = json.loads(str_req) #转换为字典类型
print(dic_data)
# TODO:解析不同的数据,并且通过数据库返回不同数据
return "Result"
if __name__=='__main__':
print(app.url_map) # 打印url的路由映射
app.run(host='127.0.0.1',port=5566,debug=False)
4.服务器对数据库进行处理
以登录请求为例子:
可以对函数进行封装,将服务器接收到的数据传递到此处进行处理,返回结果即可
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import scoped_session
from sqlalchemy.dialects.mysql import INTEGER, DATETIME, REAL, TEXT, VARCHAR,BLOB
from sqlalchemy import Table, Column, ForeignKey, MetaData
from sqlalchemy.orm import mapper, sessionmaker
from sqlalchemy import func
class UserLogin():
def __init__(self) -> None:
#连接数据库
#初始化数据库连接# '数据库类型+数据库驱动名称://用户名:口令@机器地址:端口号/数据库名'
self.url = sql_url
engine = create_engine(self.url,encoding="utf-8",echo=False)
#创建session类型
DBSession = sessionmaker(bind=engine)
#创建session对象
self.session = DBSession()
def login(self,username,pwd):
sql_str = "SELECT * FROM account WHERE username='"+str(username) +"' and pwd='"+str(pwd)
print(sql_str)
try:
cursor = self.session.execute(sql_str)
result = cursor.fetchall()
if(len(result) == 0):
return "登录失败"
except Exception as e:
print(e)
return "登录失败!"
return "登录成功"