Har 的介绍和 GPT 的初步分析(一)
2022 年 11 月,OpenAI 发布了他们划时代的产品:ChatGPT。从它出生起,我就对这个神秘的,像黑盒子一样的问答机器人充满了好奇.
- 它是如何拥有如此之长的上下文,以至于一个对话再经过多轮消息后,他仍然保留最开始的记忆.
- 它是如何生成图片的?为什么他能区分应该生成图片还是输出文字?
- 它是如何调用 Function Calling 的? 它是如何能够运行代码的?运行代码的时候能保证安全吗?
- 为什么有时候 ChatGPT 甚至会记得不同 Conversation 中的消息?
- 它是如何调用天气工具查看天气,如何调用联网工具获取网络信息的呢?
这些问题不断的缠绕着我,终于我决定对 ChatGPT 下手了.
首先先来介绍一下本文使用的工具,通常我们会用浏览器的 F12 打开 Chrome dev Tools 的 network 来查看访问一个网站的请求和响应.
但是 ChatGPT 包含的请求和响应种类相当的多,在同一个 conversation 下第一次发送 Message 和第二次发送 Messag 会不会有什么不同?生成图片,查询网页,文本输出每次产生的 Response 有什么不同?
并且 ChatGPT 使用了一种 SSE 的响应式返回,他会每次会全量更新,在这种海量数据下人工的手动分析显得非常的困难和费力.
所以引出本文使用到分析 Request
和 Response
的工具 Har
文件.
什么是 HAR 文件?
HAR(HTTP Archive,HTTP 存档文件)文件是一种记录网络浏览器和服务器之间所有通信的格式。它主要用于记录和分析网络请求和响应,帮助开发者、测试人员和网络分析师了解和调试网页性能问题。生成 HAR 文件的方式有几种,常见的方法包括使用浏览器的开发者工具(如 Chrome DevTools),通过命令行工具(如 curl
或 wget
配合 HAR 扩展)生成,或使用自动化测试框架(如 Selenium 和 Puppeteer)来记录网络活动。或者是使用抓包工具,比如 Fiddler
以及 ProxyMan
HAR 文件的用途
- 性能分析:通过分析 HAR 文件,可以识别网页加载的瓶颈,例如哪些资源加载时间过长。
- 问题诊断:当用户报告网页加载或交互问题时,可以通过 HAR 文件重现并诊断问题。
- 安全分析:HAR 文件可以显示所有的网络请求和响应,包括敏感数据传输,帮助识别潜在的安全漏洞。
- 日志记录:在开发和测试过程中,HAR 文件可以作为网络活动的日志,记录不同时间点的网络状态。
HAR 文件的结构
一个 HAR 文件包含多个部分,每个部分都记录了不同类型的信息。以下是 HAR 文件的主要结构和内容:
- log:这是 HAR 文件的根对象,包含了整个记录的基本信息。
- version:HAR 文件格式的版本号。
- creator:创建 HAR 文件的工具信息,包括工具名称和版本。
- pages:一个数组,包含所有页面的信息。
- entries:一个数组,包含所有的 HTTP 请求和响应信息。
- pages:记录了每个页面的基本信息。
- startedDateTime:页面开始加载的时间。
- id:页面的唯一标识符。
- title:页面的标题。
- pageTimings:页面加载的时间信息。
- entries:记录了每个 HTTP 请求和响应的详细信息。
- startedDateTime:请求开始的时间。
- time:请求和响应的总时间。
- request:请求的详细信息,包括方法、URL、HTTP 版本、头信息和数据负载。
- response:响应的详细信息,包括状态、HTTP 版本、头信息和数据负载。
- cache:缓存的相关信息。
- timings:请求的时间信息,包括重定向时间、DNS 解析时间、连接时间等。
如何分析 HAR 文件
分析 HAR 文件通常涉及检查每个请求和响应的详细信息,以识别潜在的问题。以下是一些常见的分析步骤:
- 检查总加载时间:查看页面的总加载时间,识别是否有明显的延迟。
- 分析慢速请求:找出哪些请求花费的时间最多,检查这些请求的详细信息,包括服务器响应时间和数据传输时间。
- 检查错误请求:查看是否有任何失败的请求,检查响应状态码和错误消息,以确定问题的根源。
- 优化资源加载:检查静态资源(如图片、CSS、JavaScript)的加载时间,考虑使用压缩、缓存和内容分发网络(CDN)来优化加载时间。
实战
下面是一段 python
代码,用于记录所有 https://chatgpt.com/backend-api/conversation
的 POST
的 Request
和 Response
. 包括 Header
和 Body
import json
import re
import logging
class HarExtractor:
def __init__(self, har_file_path):
self.har_file_path = har_file_path
self.logger = logging.getLogger(__name__)
self.logger.setLevel(logging.INFO)
# 移除所有处理程序,包括根记录器的处理程序
for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)
# 添加文件处理程序
handler = logging.FileHandler('HarExtract.log', mode='w', encoding='utf-8')
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
self.logger.addHandler(handler)
def load_har_file(self):
with open(self.har_file_path, 'r', encoding='utf-8') as f:
self.har_data = json.load(f)
@staticmethod
def decode_unicode_escape(json_str):
return json_str.encode('utf-8').decode('unicode_escape')
def extract_entries(self):
URL_pattern = re.compile(r'^https://chatgpt.com/backend-api/conversation$')
Method_pattern = re.compile(r'^POST$')
for entry in self.har_data['log']['entries']:
request = entry['request']
response = entry['response']
if URL_pattern.match(request['url']) and Method_pattern.match(request['method']):
self.log_request_response(request, response, entry['time'])
def log_request_response(self, request, response, time):
self.logger.info(f"Request URL: {request['url']}")
self.logger.info(f"Request Method: {request['method']}")
self.logger.info(f"Response Status: {response['status']} {response['statusText']}")
self.logger.info(f"Time: {time} ms")
self.logger.info("Request Headers:")
for header in request['headers']:
self.logger.info(f" {header['name']}: {header['value']}")
if 'postData' in request:
self.logger.info("Request Body:")
self.logger.info(request['postData']['text'])
self.logger.info("Response Headers:")
for header in response['headers']:
self.logger.info(f" {header['name']}: {header['value']}")
if 'text' in response['content']:
self.logger.info("Response Body:")
response_body = HarExtractor.decode_unicode_escape(response['content']['text'])
self.logger.info(response_body)
self.logger.info("-" * 80)
if __name__ == "__main__":
har_extractor = HarExtractor('SourceHar/chatgpt_firefox.har')
har_extractor.load_har_file()
har_extractor.extract_entries()
在你运行完这个文件之后,会多出一个 HarExtract.log
文件,里面详细的包含了你询问 ChatGPT 时,他发送的所有 Header
和 Body
. 里面包含 OAI-Device-Id
, OpenAI-Sentinel-Arkose-Token
, OpenAI-Sentinel-Turnstile-Token
, OpenAI-Sentinel-Proof-Token
,Cookie
以及 AccessToken
.
目前有很多开源项目,通过 Har 文件来将 ChatGPT 的 Web
转 API
.当然我们是遵纪守法的好公民.我们只是来学习一下 ChatGPT 的请求体和响应体,来看看 ChatGPT 到底是如何运作的.
请收看第二章, Har(二) Request Body
求个小心心