自由学习记录(44)
设置一下自动缩进调整
但现在问题来了,这里的发送是一次性发送的,
应该是服务器发的API有点问题,现在key内有时候有字母出现了这是在记事本里的样子
之间是空格
VScode里变成了下划线
官方APIkey里也是下划线
从官方key(下划线)--粘贴到记事本(空格)---VScode(下划线)
(记事本里粘贴出来的这个空格,在VScode里居然直接是下划线_)
VSCO对粘贴上去的key动了手脚(之后又粘贴的时候又没有出现问题,,奇怪,,创了新key测了几次也没问题,,,什么情况,,总之都归为apikey的复制粘贴问题吧)
重点还是APIkey的正确性,,在curl进行比对之后,发现用原来的key可以但在VScode里粘贴的key却是无效的,,应该是VScode的问题了
也是够奇怪的,在curl也运行不了,是哪里出问题了
重定向(无效)
换设置头的方法(无效)
比对curl(测试)
可以以此判断APIkey在服务器到底还有没有实际的可以生效
这种情况下说明还是有响应的,只不过不让访问具体的内容而已,
HTTP 401 错误 - 未授权: (Unauthorized)
Web服务器认为,客户端发送的 HTTP 数据流是正确的,而相关信息 尚未被提供, 或 已提供但没有通过授权测试。
这就是通常所知的“ HTTP 基本验证 ”。 需客户端提供的验证请求在 HTTP 协议中被定义为 WWW – 验证标头字段 (WWW-Authenticate header field)
---------
RestSharp 是一个 C# 语言的 HTTP 客户端库,用于简化 REST API 请求 的发送和处理。它是 HttpClient
和 HttpWebRequest
的 高级封装,让你更方便地发送 HTTP 请求(GET、POST、PUT、DELETE 等)
- 检测
finish_reason=stop
关闭连接 - 如果要取消请求,可以
Abort()
stream=false
:服务器只发送一次完整的 JSON,然后立即关闭连接。
stream=true
:服务器会持续发送数据(SSE 事件流),直到完成,但这个过程中客户端不能再发送新请求,只能等待服务器继续推送数据。
成功了,终于找到对的格式了,可以在curl上得到SSE响应
curl https://api.deepseek.com/chat/completions \-H "Content-Type: application/json" \-H "Authorization: Bearer <DeepSeek API Key>" \-d '{"model": "deepseek-chat","messages": [{"role": "system", "content": "You are a helpful assistant."},{"role": "user", "content": "Hello!"}],"stream": false}'
为什么不单行输出,总是不能在cmd运行:这种更通用,适用于 Linux / Mac 终端 和 PowerShell(但不适用于 Windows cmd
)
Postman 的 "Code Snippet"(代码片段)功能!
它可以 自动生成不同编程语言的 API 请求代码,让开发者 不用手写 API 调用代码,直接复制粘贴使用。
Fork Collection(复制请求集):你可以点击 "Fork collection" 把这个 API 请求复制到自己的 Postman 里,方便测试。
官方或流行的 API 调用示例,它们帮助开发者快速测试和调用 OpenAI API
-X POST
的作用
-X POST
是 curl
里的 请求方法,它告诉服务器 "我要发送 POST
请求"。
默认情况下,curl
发送的是 GET
请求,但 OpenAI API 不支持 GET
,所以你必须明确指定 POST
。
浏览器地址栏只能发 GET
,不能发送 POST
请求体(JSON)
JSON 不能直接放 URL
messages=[{"role":"user","content":"Hello!"}]
里的"
和{}
不能直接放 URL,会被 URL 编码成%22
、%7B
等,导致错误。
Postman 是一个 API 测试工具,允许你手动输入 API 请求,发送 POST
、GET
、PUT
等请求,并查看 API 的实时返回结果。
它比浏览器地址栏强大,适合测试 OpenAI API 的 SSE 响应,因为它支持:
- 发送
POST
请求 - 实时查看 OpenAI 的流式数据
- 调整请求头(Headers)
- 调试 API 响应
Postman: The World's Leading API Platform | Sign Up for Free
- 浏览器地址栏 (
URL
) 只支持GET
请求,而 OpenAI API 流式响应(SSE) 需要POST
请求,所以 不能直接在地址栏测试 SSE。 - 即使你用
fetch()
或XMLHttpRequest()
在浏览器控制台发送POST
请求,浏览器默认不会正确解析 SSE 流式数据,而是等它全部返回后才显示。
想直接在 浏览器地址栏 或 Postman 里测试 OpenAI API 的 SSE 响应,URL 不能直接支持 POST
请求带 JSON 数据,你需要使用 curl
或 API 测试工具(如 Postman、Insomnia)。
但是,你可以使用 URL Encoded 格式 来模拟请求。
-----------
也就是说,只要可以在url上面,以正确的格式发送请求,可以得到消息的回复,在unity的Request传输上就一定没有问题了----ps:还是GPT回的快啊
还有关于代理的问题,现在也了解的更多了,也是进步了,以及格式之类的,刚开始看到这些很陌生,现在对整个http请求的过程都更熟悉了
---------
这下GPTAPI也可以访问了,不存在在访问上被禁止的问题了
在命令行窗口,存在语法的问题,,而官方 reference里并没有注意这个,,才会出现这种问题
在unity 的unitywebrequest类里,因为这些都被自动的整理好了,所以自然没有出现这些问题
curl的语法问题,,,,,,原来是这样
Windows cmd
里会报错,主要因为 换行符 \
语法不兼容。
Resolve的跳过DNS,直接访问
发多条会有历史记录,而且AI只会回复最后body里的最后一条message{}
这下就可以真正的测试,OpenAI的API到底可不可以用
curl -x http://127.0.0.1:7890 -H "Authorization: Bearer sk-你的API密钥" -v https://api.openai.com/v1/models
改成clash的端口,这样就不需要每次都加-x补上http访问的形式 了
curl
和浏览器走的是不同的网络!
curl
返回的是 IPv6 地址,通常是你的本地 ISP(网络提供商)分配的。- 如果
curl
走了 VPN,它的 IP 应该和浏览器一样IPV4。
What Is My IP Address? - ifconfig.me
curl
返回的 IP 和浏览器返回的 IP 不一样,说明 curl
和浏览器走的是不同的网络。
- 如果 VPN 只需要在开机时启动,用
schtasks(推荐)
。 - 如果 VPN 需要一个后台服务保持运行,用
winsw
。
schtasks.exe
是 Windows 自带的 任务计划程序,用于定期运行某些任务(比如启动 VPN 或TUN
服务)。- VPN 软件可能使用
schtasks
在系统启动时自动运行 VPN 服务,确保TUN
设备始终可用。
在 TUN
模式下,你不需要手动设置代理,系统会自动将所有流量转发到 VPN 服务器。
ping www.google.com
失败 或 curl
无法访问 Google,而 浏览器可以正常访问,那么你的网络可能被部分屏蔽
过了太久了,自己写的代码都不敢信了,所以一定要有一些硬性的函数,不然乱糟糟的,又想重新写
----这个流响应 没给我做成真的是萎了一样,,都不晓得该干什么了
InvokeRepeating
是 Unity MonoBehaviour
提供的一个方法,它用于在一定间隔内重复调用某个方法。
直接把这个第一人称控制的组件禁用掉,鼠标就可以正常使用了
先声明着用,对于定义的引用,之后记得再补上去
ctrl+F,VScode的文本搜索
插件而已,不好用的话不建议魔改,大不了找别的插件
正常的这样给GPTAPI发送的请求,是不保存记忆的
回调函数传入的匿名函数,直接在里面写脚本
否则用using圈套
对于协程的使用,这样则分离开了协程对回复的获取,以及返回的字符需要的处理
using System.Collections;
using UnityEngine;public class CoroutineExample : MonoBehaviour
{private Coroutine myCoroutine; // 用于存储协程的成员变量void Start(){// 启动协程,并存储返回的 Coroutine 实例myCoroutine = StartCoroutine(MyCoroutine());}void Update(){if (Input.GetKeyDown(KeyCode.Space)){StopMyCoroutine();}}IEnumerator MyCoroutine(){while (true){Debug.Log("协程运行中...");yield return new WaitForSeconds(1f);}}void StopMyCoroutine(){if (myCoroutine != null) // 确保协程存在{StopCoroutine(myCoroutine);myCoroutine = null; // 清空引用,避免重复停止Debug.Log("协程已停止");}}
}
为什么要用 Coroutine
作为成员变量?
- 方便 暂停、停止或重启 某个特定的协程,而不影响其他协程。
- 避免
StopCoroutine("MethodName")
这种字符串方式(不推荐)。 - 更清晰地管理 协程的生命周期。
协程的关闭
using System.Collections;
using UnityEngine;public class CoroutineStopExample : MonoBehaviour
{private Coroutine myCoroutine; // 保存协程的引用void Start(){myCoroutine = StartCoroutine(MyCoroutine());}void Update(){if (Input.GetKeyDown(KeyCode.Space)) // 按下空格键停止协程{StopCoroutine(myCoroutine);Debug.Log("协程已停止");}}IEnumerator MyCoroutine(){while (true){Debug.Log("协程执行中...");yield return new WaitForSeconds(1f);}}
}
在 Unity 之外的 C#(比如 .NET 应用程序),一般使用 async/await
进行异步编程,而不是 IEnumerator
。
----
再看看网上的教程吧
放弃了,,真的知道的信息太少 了,盲问AI又对消息的准确度怀疑,给的代码还经常错,,就一个异步流而已居然会这么难做,,,,,还是不甘心,但没办法了,还是需要沉淀,要扎实
---------
Socket可以支持 WebSocket,但不是专门为 WebSocket 设计,是底层网络通信类,可用于 WebSocket 但也可以用于 TCP/UDP。
HttpClient发送 HTTP 请求,适用于 短连接,一次请求对应一次响应。
--------
WebSockets 也是流式通信的一种方式,不同于 SSE 只能服务器推送,WebSockets 支持全双工通信(服务器和客户端都可以主动发送消息)。在 WebSocket 连接中,数据通常是**帧(frames)**的形式:
- 文本帧(Text Frame):用于发送 JSON、字符串数据。
- 二进制帧(Binary Frame):用于发送二进制数据(如音频、图片)。
- 控制帧(Control Frame):用于管理 WebSocket 连接(如 Ping/Pong 保持连接)。
不过,OpenAI API 目前没有提供 WebSockets 方式。
这个真的是忽略 了,API会自定义流式传回数据的类型,,如果拿httpclient来接受,是接不了的
流式响应的数据传输通常是分多种类型的,具体取决于协议和服务器实现方式。
在 OpenAI API 的 stream=true
模式下,它采用 Server-Sent Events (SSE),在流式数据中不同部分可能有不同的格式。
默认情况下,HttpClient
的 GetStringAsync()
或 ReadAsStringAsync()
会等待服务器返回整个 HTTP 响应后才解析数据,这就导致:
- 普通 HTTP 响应没问题,因为数据是一次性返回的。
- SSE/流式数据有问题,因为服务器是一段一段地推送数据,但
HttpClient
默认不会逐步处理,而是等整个响应结束后才返回。
chatgpt stream 实时输出功能实现原理 SSE(Server-send events)_哔哩哔哩_bilibili
SSE请求
----
感觉这个会很关键
生成和使用异步流 - C# | Microsoft Learn
在C#是不是也有这样的类?只是因为我没了解
StreamReader.ReadLine
的工作原理
-
换行符检测:
-
当检测到换行符(
\n
或\r\n
)时,ReadLine
会将缓冲区中的字符 组合成一个字符串并返回。 -
换行符本身不会被包含在返回的字符串中。
-
-
流的结束:
-
如果流中没有更多的数据可读,
ReadLine
会返回null
。
-
openai返回的 流中的每次response整体信息,都符合json格式(httpContent属性就在里面),
所以需要Json解析器才能得到数据(httpContent的),而在解析这一步,已经脱离了网络传输的过程
既然是在stream类下,默认的这些方法都是在stream传输的情况下了
异步读取字节流,这里的异步相对于没有异步进行的Read函数来说,只是不会卡在这里等待
同步的 Read()
也会符合流的 逐步读取流式数据,区别在于 调用线程会被阻塞,直到有数据可读或流结束。
Read()
只会读取 当前可用的字节,不会等完整响应。- OpenAI API 生成一部分内容,就会立即发送,这时候
Read()
读取当前收到的部分。 - 如果数据还没来,
Read()
会等待,直到 API 发送新的数据,再继续读取。
HttpContent
是 请求体和响应体的通用封装,当你接受 API 传回的 HttpResponseMessage
时,responsemessage本身就已经装有了 HttpContent
属性,
只不过可以message.content.(然后调用里面的读取方法)
完整的 JSON 数据 存放 在 HttpContent
里面,但 HttpContent
只是 一个包装,不会自动解析 JSON,你需要Read出Content里的json字符串,用newtonsoft再解析出body里的信息:
API返回的完整http响应 是在返回的httpresponsemessage里,而Content是框住了里面的json数据格式体
GPT在网络传输上真的完全做不了,确定了AI大致的能力范围,也放心了,搜索的信息有一些过时了,但是本质还保留 了,配合当前的文档去了解一下就可以
College Stuff
JSP,web开发
【Java教程】Servlet+JSP快速入门JavaWeb开发_哔哩哔哩_bilibili
项目的部署,就是在本地配置服务器(Tomcat),如果不部署项目,外界是不能访问自身的服务器的内容的
解压之后可以看到这样的一个目录结构,
bin目录中有很多可以运行的脚本,包括启动脚本和结束脚本,
config目录中是tom cat的配置文件,我们可以修改tomcat的默认配置,
lib目录中是tom cat需要用到的 jar 包,
logs目录中指的是tomcat运行时的日志,
temp目录是一个临时目录,
webapps目录是tom cat的工作目录,我们写好的代码就需要放到webapps中,
如果想让用户通过浏览器访问某一个资源的话,
那么这个资源必须放在web服务器,也就是tomcat中才可以被用户访问,
并且必须要放在web apps的对应目录下
bin文件夹下是Tomcat的startup 和shutdown
一次只能startup一个Tomcat,再startup会提示端口号被占用
idea创建项目,一个项目可以选择是否配置Tomcat但默认不配置,需要自己选择
html是静态的,不能从服务器上获取动态的数据
在idea中创建java的web项目,要在这里选择,,创建工件
之后出现这个至关重要的web文件夹
每个项目都需要单独的选择是否配置,也就是每个项目都是独立的,并不是什么全局设置
与之后的项目是分开的,放心设置即可
写好jsp之后就可以去运行了,但是还需要可以访问的服务器
也就是我们自己需要配置上去的Tomcat
url很关键,是访问的关键
许多 Web 服务器(如 Tomcat)中,index.jsp 通常被配置为默认首页。当你访问根 URL 时,服务器会自动查找并显示 index.jsp。如果你使用其他名称,可能需要在 URL 中明确指定。
JSP本质上是先被翻译成Servlet,然后由服务器编译和执行。这意味着每次请求JSP页面时,都会执行相应的Java代码来生成HTML响应。
JSP允许Java代码直接嵌入到HTML中,这种灵活性使得开发者能够方便地创建动态Web页面。
---------
Tomcat 默认访问的是 web.xml
配置的欢迎页面(Welcome File),或者是 webapps
目录下的 index.jsp
或 index.html
之类的文件,而你的 hello.jsp
不是默认首页,因此需要在 URL 后面手动添加 /hello.jsp
才能访问。
IDEA 运行 Tomcat 时的 Web 目录
如果你在 IDEA 里使用 Tomcat 配置(Run Configuration) 运行 Web 项目,它不会直接使用 webapps
目录,而是:
- 在
out/artifacts/
目录下生成一个独立的部署目录 - 在 IDEA 配置的 Tomcat 运行环境中加载这个目录
举个例子,你的 IDEA Web 项目可能在:
关键点:
- IDEA 运行 Tomcat 时,不会使用
Tomcat/webapps/
,而是将你的 Web 项目打包并映射到out/artifacts/.../
目录。 - 你的 Web 项目 URL 依然是
http://localhost:8080/your_project/
,但实际访问的是out/artifacts/YourProject_Web_exploded/
里的文件。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Print Table</title><style>table {width: 50%;border-collapse: collapse;}th, td {border: 1px solid black;padding: 8px;text-align: center;}th {background-color: #f2f2f2;}</style>
</head>
<body><h2>Print Table Example</h2><table><tr><th>Row</th><th>Value</th></tr><% for (int i = 1; i <= 5; i++) { %><tr><td><%= i %></td><td>Data <%= i %></td></tr><% } %></table>
</body>
</html>
如果不使用 JSP,而是单纯的 HTML 代码,可以写成:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>静态表格</title><style>table {border-collapse: collapse;width: 50%;text-align: center;}th, td {border: 1px solid black;padding: 10px;}th {background-color: #f2f2f2;}</style>
</head>
<body><h2>静态 5×5 表格</h2><table><tr><th>行/列</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th></tr><tr><th>1</th> <td>1</td> <td>2</td> <td>3</td> <td>4</td> <td>5</td></tr><tr><th>2</th> <td>2</td> <td>4</td> <td>6</td> <td>8</td> <td>10</td></tr><tr><th>3</th> <td>3</td> <td>6</td> <td>9</td> <td>12</td> <td>15</td></tr><tr><th>4</th> <td>4</td> <td>8</td> <td>12</td> <td>16</td> <td>20</td></tr><tr><th>5</th> <td>5</td> <td>10</td> <td>15</td> <td>20</td> <td>25</td></tr></table>
</body>
</html>
方式 | 优点 | 缺点 |
---|---|---|
JSP 动态生成表格 | 可以通过循环自动生成内容,适合大规模数据 | 代码混杂 HTML 和 Java,不够直观 |
纯 HTML 静态表格 | 代码结构清晰,浏览器直接解析 | 数据是手写的,修改和扩展困难 |
JSP 页面指令以及 HTML 结构的基本作用
这是 JSP 指令,用于告诉服务器如何处理这个 JSP 文件。
(1)<%@ page ... %>
指令
-
page
是 JSP 指令之一,用于控制 JSP 页面的一些属性。
(2)language="java"
-
指定 JSP 页面使用的编程语言,这里是 Java。
-
事实上,现在的 JSP 默认就是 Java,所以通常可以省略。
(3)contentType="text/html; charset=UTF-8"
-
contentType="text/html"
说明 返回的内容是 HTML 格式。 -
charset=UTF-8
说明 使用 UTF-8 字符编码,确保页面可以正确显示中文、特殊符号等。
(4)pageEncoding="UTF-8"
-
指定 JSP 文件本身的编码,确保 JSP 源代码被正确解析,避免乱码。
contentType
决定 浏览器如何解析 JSP(来自Tomcat) 生成的网页,pageEncoding
决定 服务器如何读取 JSP 源文件(就在Tomcat里)。
(1)<!DOCTYPE html>
-
声明当前文档是 HTML5,让浏览器以标准模式解析网页,而不是兼容模式(可能会导致 CSS、JS 解析异常)。
(2)<html> ... </html>
-
html
标签包裹整个网页,表示网页的起始和结束。 -
里面通常包含两个主要部分:
head
和body
。
<head> ... </head>
(头部)
head
里放置 网页的元数据,不会直接显示在页面上,常见内容包括:
meta charset="UTF-8"
:指定游览器的这个生成的网页的编码格式,防止在网页上乱码。title
:定义网页标题,显示在浏览器标签上。link
:用于引入外部 CSS,控制页面样式。script
:引入外部 JavaScript,添加交互功能。
<body> ... </body>
(主体)
body
里的内容是 网页的主要显示部分,浏览器会直接渲染这里的内容。
HTML基础语法_哔哩哔哩_bilibili
网页保持可以解析就解析展示,遇到哪里不对头,直接扔一边,大不了不显示(而且也并不影响,因为展示是独立的)
HTML 教程
关于html的语法讲解,可以在网上搜到相关的规定
html文件是不需要有网咯连接,直接就可以展示的
jsp是编译出可以展示的网页,是服务器需要自己先处理,然后把产生的结果html交给游览器展示
html语法解析
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Print Table</title><style>-----------开始定义CSS样式,CSS用于控制网页的外观和格式table {--------开始定义<table>标签的样式width: 50%;---------设置表格的宽度为页面宽度的50%border-collapse: collapse;-------表格的边框合并为一个单一的边框,而不是双线}th, td {----------------------定义<th>(表头单元格)和<td>(表格单元格)的样式border: 1px solid black;--设置单元格 的边框为 1像素的黑色实线padding: 8px;-------------设置 单元格 内容与边框之间的 间距为8像素text-align: center;-------单元格 内容居中对齐}th {------------------------------定义<th>(表头单元格)的样式background-color: #f2f2f2;----表头单元格的背景颜色为浅灰色(十六进制颜色#f2f2f2)}</style>
</head>
<body>
<h2>Print Table Example</h2>------添加一个二级标题
<table>-----------------------------开始定义一个表格<tr>----表格的一行<th>Row</th>-----------表头单元格,添加一个“Row”<th>Value</th>---------再添加一个“Value”</tr><% for (int i = 1; i <= 5; i++) { %><tr><td><%= i %></td><td>Data <%= i %></td></tr><% } %>
</table>
</body>
</html>
是这样前后对应,表示下面要开始对 i 的循环使用
额外的实验测试
这里就会直接突出显示一列