从0解构tinyWeb项目--(Day:7)

0 阅读4分钟

今日任务

image.png

image.png

因为默写RecordVisit实在是有点多了,后面每个GORM操作决定放在明天完成,刚好明天的任务不是很多

今日内容

getClientIP函数

image.png

这个函数主要就是获取用户ip的,而且还提供了三层获取方法,一层一层保障

用户ip很重要,从后面Recordvisit就可以知道

第一个X—Forwarded-For(代理后面最常用)

代码中,这里先获取并赋值xff,但是X—Forwarded-For中只有在第一个逗号之前才是我们需要获取的ip,所以这里Split(xff,",")把逗号识别成分隔符,然后把分隔的每一部分作为数组的每个元素

后面trimspace去掉多余的空格,拿到正确的ip。

第二个X-Real-IP

同上,不多说

第三个直连地址

image.png 类似这样的数据,我们不需要后面的端口,所以只需要取得冒号之前的数据

strings.LastIndex(addr, ":")找到字符串中最后一个冒号的位置并赋值给lastColon

如果没找到这个位置就返回arr[:lastColon],表示从开头取到lastColon的位置 也就是对应ip

如果没找到冒号,直接返回ip(极少见)

r.Header

image.png 这是r的请求头,除此还有熟知的r.Body,还有其他的等等,做个了解吧

image.png

RecordVisit函数(重点)(四个步骤)

image.png

image.png

image.png

步骤一:json.Decode 解析

image.png 前端传来的json数据需要一个地方储存

这里var req model.VisitRecord,req起到这个Go结构体数据容器作用

那么后面json.NewDecoder(r.Body)就是创建一个json的解码器,用于翻译让他盯着r.Body数据(没有操作只是盯着)

.Decode(&req)就是正式开始解码,然后把解析完的数据填入req这个结构体中。只有当解码出错才会有返回值于是就给了err,

后面就是发送错误信息了sendJSON(w,http.StatusBadRequest,model.ErrorResponse()) 这里w是给浏览器的笔(理解成返回是要用),http.StatusBadRequest状态码对应400(请求错误),mode.ErrorReqsponse一个错误信息的模版,大概长成如下图模样

image.png

步骤2:补全 IP(req.VisitorIP == "" 时调用 getClientIP)

image.png

首先先去空格,然后如果前端返回不了ip

启动getClientIP(一开始那个三种手段获取ip的函数)

如果还是空值,那么发送错误信息

后面还有一些关于链接数据库和一些初始化操作顺便写进来

步骤三:数据库操作(重要之重)

这里面有很多if,else分层,逻辑要弄清楚

image.png

首先我们查询的记录需要一个容器储存,类似getClientIp函数一开始 var existing model.VisitStats

后面database.Where()添加查询条件,就是去哪里找

后面"visitor_ip = ?"就是去这个字段找,“?”是占位符,实际上要填入的就是后面的req.VisitorIP

后面还需要填入,.First(&existing)就是这个作用 First()找到的第一个数据(其实也只会有一个,只是方便后面的错误处理)

,把查询到的填入existing这个结构体

那么后面result.Error!=nil注意这是第一层if,判断条件时是如果ip没访问过时也就是相当于First没有找到数据时

其中第二层if是result.Error中显示是ip没访问过,对应查询数据时初始数据(也就是这个ip没访问过,但是查询本身是有效的,返回的就是一个全是初始数据的表),注意这里是单纯的判断语句,没有实际操作

那么操作在后面。 if err:=database.Create(&newRecord).Error,这里就是把数据填进去了,(这里是go语言if语句 处理操作+处理操作出错信息的写法,在这个RecordVisit包括其他的函数中都很常见,详情见后面),这里如果操作出错,就sendJSON返回错误信息。(结构上:这里是第二层if中,if操作出错的错误处理)

那么再返回到第二层if对应的else,也就是当数据库查询出错时,

对应的返回错误信息

image.png

这里就是第一层if对应的else,也就是用户访问过,也就是需要更新数据的时候

这里对应的用了一个updates操作

那么当这个操作出错时

返回错误信息"更新访问出错",这里注意状态码其实前几次就变了,变成了500(数据库操作出错)

返回响应

image.png

这里讲一下isFirstVisit之前设置过如果首次访问就是true

所以这里判断条件为真,就是显示responseData["visit_count"] = 1,意思是设置responseData(定义的哈希表结构体)中的"visit_count" key对应的值为1

最后返回信息

至此,RecordVisit函数就完了

GetVisitStats函数(获取网站的总访问信息)

image.png

这里database.Model对应gorm中的.Model方法

然后(&model.VisitStats{})是对应的机构

select是告诉数据库要查什么

scan就是执行SQL并把结果扫描的变量中

formatted就是格式化,这里是时间格式

最后返回信息

练习

默写RecordVisit的四个步骤(好多,写了半天)

联想截图_20260425155127.jpg

联想截图_20260425155140.jpg

联想截图_20260425155146.jpg

模拟 RecordVisit 核心逻辑,实现用户手机号和名字的更新或插入

image.png