今日任务
因为默写RecordVisit实在是有点多了,后面每个GORM操作决定放在明天完成,刚好明天的任务不是很多
今日内容
getClientIP函数
这个函数主要就是获取用户ip的,而且还提供了三层获取方法,一层一层保障
用户ip很重要,从后面Recordvisit就可以知道
第一个X—Forwarded-For(代理后面最常用)
代码中,这里先获取并赋值xff,但是X—Forwarded-For中只有在第一个逗号之前才是我们需要获取的ip,所以这里Split(xff,",")把逗号识别成分隔符,然后把分隔的每一部分作为数组的每个元素
后面trimspace去掉多余的空格,拿到正确的ip。
第二个X-Real-IP
同上,不多说
第三个直连地址
类似这样的数据,我们不需要后面的端口,所以只需要取得冒号之前的数据
strings.LastIndex(addr, ":")找到字符串中最后一个冒号的位置并赋值给lastColon
如果没找到这个位置就返回arr[:lastColon],表示从开头取到lastColon的位置 也就是对应ip
如果没找到冒号,直接返回ip(极少见)
r.Header
这是r的请求头,除此还有熟知的r.Body,还有其他的等等,做个了解吧
RecordVisit函数(重点)(四个步骤)
步骤一:json.Decode 解析
前端传来的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一个错误信息的模版,大概长成如下图模样
步骤2:补全 IP(req.VisitorIP == "" 时调用 getClientIP)
首先先去空格,然后如果前端返回不了ip
启动getClientIP(一开始那个三种手段获取ip的函数)
如果还是空值,那么发送错误信息
后面还有一些关于链接数据库和一些初始化操作顺便写进来
步骤三:数据库操作(重要之重)
这里面有很多if,else分层,逻辑要弄清楚
首先我们查询的记录需要一个容器储存,类似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,也就是当数据库查询出错时,
对应的返回错误信息
这里就是第一层if对应的else,也就是用户访问过,也就是需要更新数据的时候
这里对应的用了一个updates操作
那么当这个操作出错时
返回错误信息"更新访问出错",这里注意状态码其实前几次就变了,变成了500(数据库操作出错)
返回响应
这里讲一下isFirstVisit之前设置过如果首次访问就是true
所以这里判断条件为真,就是显示responseData["visit_count"] = 1,意思是设置responseData(定义的哈希表结构体)中的"visit_count" key对应的值为1
最后返回信息
至此,RecordVisit函数就完了
GetVisitStats函数(获取网站的总访问信息)
这里database.Model对应gorm中的.Model方法
然后(&model.VisitStats{})是对应的机构
select是告诉数据库要查什么
scan就是执行SQL并把结果扫描的变量中
formatted就是格式化,这里是时间格式
最后返回信息