Cookie

Cookie是什么

HTTP是无状态协议,服务器不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否由同一个客户端发出

Cookie就是解决HTTP协议无状态的方案之一,中文是小甜饼的意思

Cookie实际上就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求

Cookie由服务器创建,并发送给浏览器,最终由浏览器保存

Cookie的用途

保持用户登录状态

Cookie的缺点
/*
不安全,明文
增加带宽消耗
可以被禁用
Cookie有上限
*/
Cookie的使用

测试服务器发送cookie给客户端,客户端请求时携带cookie

package main

import (
"fmt"
"github.com/gin-gonic/gin"
) func main() {
// 1.创建路由
// 默认使用了2个中间件Logger(), Recovery()
r := gin.Default() // 服务端要给客户端
r.GET("cookie", func(c *gin.Context) {
// 获取客户端是否携带cookie
cookie,err := c.Cookie("key_cookie")
if err != nil {
cookie = "NotSet"
// 给客户端设置cookie
// maxAge int, 单位 s
// path cookie 所在目录
// domain string 域名
// secure 是否只能通过https访问
// httponly bool 是否允许别人通过js获取自己的cookie
c.SetCookie("key_cookie","value_cookie",60,"/","localhost",false,true)
}
fmt.Printf("cookie的值是: %s\n",cookie)
})
r.Run()
}

模拟实现权限验证中间件

package main

import (
"github.com/gin-gonic/gin"
"net/http"
) func AuthMiddleWare() gin.HandlerFunc {
return func(c *gin.Context) {
if cookie, err := c.Cookie("abc"); err == nil {
if cookie == "123" {
c.Next()
return
}
}
// 返回错误
c.JSON(http.StatusUnauthorized,gin.H{"error":"err"})
c.Abort()
return
}
} func main() {
// 1.创建路由
// 默认使用了2个中间件Logger(), Recovery()
r := gin.Default()
r.GET("/login", func(c *gin.Context) {
c.SetCookie("abc","123",60,"/","localhost",false,true)
c.String(200,"Login success!")
}) r.GET("/home",AuthMiddleWare(), func(c *gin.Context) {
c.JSON(200,gin.H{"data":"home"})
})
r.Run()
}

Session

Session是什么

Session可以弥补Cookie的不足, Session必须依赖于Cookie才能使用, 生成一个SessionID放在Cookie里传到客户端就可以.

Session中间件开发

设计一个通用的Session服务, 支持内存存储和redis存储

Session模块设计

/*
本质上k-v系统,通过key进行增删改查.
Session可以存储在内存或者redis(2个版本)
*/

Session接口设计

/*
Set()
Get()
Del()
Save() session存储, redis的实现延迟加载
*/

SessionMgr接口设计

/*
Init() 初始化,加载redis地址
CreateSession() 创建一个新的session
GetSession() 通过SessionID获取对应的Session对象
*/

MemorySession设计

/*
定义MemorySession对象 (字段: SessionID, 存kv的map,读写锁)
构造函数,为了获取对象
Set()
Get()
Del()
Save()
*/

MemorySessionMgr设计

/*
定义MemorySessionMgr对象(字段: 存放所有session的map, 读写锁)
构造函数
Init()
CreateSession()
GetSession()
*/

RedisSession设计

/*
定义RedisSession对象(字段: sessionID,存kv的map, 读写锁, redis连接池, 记录内存中map是否被修改的标记) 构造函数 Set(): 将session存到内存中的map
Get(): 取数据,实现延迟加载
Del()
Save(): 将session存到redis
*/

RedisSessionMgr设计

/*
定义RedisSessionMgr对象(字段: redis地址,redis密码, 连接池,读写锁, 大map)
构造函数
Init()
CreateeSession()
GetSession()
*/

session.go


数据库操作

sql
CREATE TABLE `book` (
`id` int(50) NOT NULL AUTO_INCREMENT,
`title` varchar(50) DEFAULT NULL,
`price` int(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
结构
 tree
.
├── book
├── db
│   └── db.go
├── go.mod
├── go.sum
├── main.go
├── model
│   └── book.go
└── templates
├── book_list.html
└── new_book.html
db

db.go

// 查询单条数据示例
package db import (
"database_test1/model"
"fmt"
_ "github.com/go-sql-driver/mysql" // init()
"github.com/jmoiron/sqlx"
) // Go连接MySQL示例 var db *sqlx.DB // 是一个连接池对象 func InitDB() (err error) {
// 数据库信息
// 用户名:密码@tcp(ip:端口)/数据库的名字
dsn := "test:ZHOUjian.22@tcp(121.36.43.223:3306)/book?charset=utf8" // 连接数据库
db, err = sqlx.Connect("mysql", dsn)
if err != nil {
return
}
db.SetMaxOpenConns(10) // 设置数据库连接池的最大连接数
db.SetMaxIdleConns(5) // 设置最大空闲连接数
return
} func QueryAllBook() (bookList []*model.Book,err error) {
sqlStr := "select id,title,price from book"
err = db.Select(&bookList,sqlStr)
if err != nil {
fmt.Println("查询失败")
return
}
return
} func InsertBook(title string,price int64) (err error) {
sqlStr := "insert into book(title,price) values(?,?)"
_, err = db.Exec(sqlStr,title,price)
if err != nil {
fmt.Println("插入失败")
return
}
return
} func DeleteBook(id int64) (err error) {
sqlStr := "delete from book where id =?"
_,err = db.Exec(sqlStr,id)
if err != nil {
fmt.Println("删除失败")
return
}
return
}
model

book.go

package model

type Book struct {
ID string `db:"id"`
Title string `db:"title"`
Price int64 `db:"price"`
}
template

book_list.html

{{ define "book_list.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>书籍列表</title>
</head>
<body>
<div><a href="/book/new">添加新书</a></div>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>title</th>
<th>price</th>
<th>操作</th>
</tr>
</thead> <tbody>
{{ range .data}}
<tr>
<td>{{ .ID }}</td>
<td>{{ .Title }}</td>
<td>{{ .Price }}</td>
<td><a href="/book/delete?id={{ .ID }}">删除</a></td>
</tr>
{{ end }} </tbody> </table> </body>
</html>
{{ end }}

new_book.html

{{ define "new_book.html" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加图书信息</title>
</head>
<body>
<form action="/book/new" method="POST"> <div>
<label>书名:
<input type="text" name="title">
</label>
</div> <div>
<label>价格:
<input type="number" name="price">
</label>
</div> <div>
<input type="submit" value="点我">
</div> </form> </body>
</html>
{{ end }}
Main.go
package main

import (
"database_test1/db"
"github.com/gin-gonic/gin"
"net/http"
) func main() {
// 初始化数据库
err := db.InitDB()
if err != nil {
panic(err)
} r := gin.Default()
r.LoadHTMLGlob("./templates/*")
// 查询所有图书
r.GET("/book/list",bookListHandler)
r.Run()
} func bookListHandler(c *gin.Context) {
bookList ,err := db.QueryAllBook()
if err != nil {
c.JSON(http.StatusOK,gin.H{
"code":1,
"msg":err,
})
return
} // 返回数据
c.HTML(http.StatusOK,"book_list.html",gin.H{
"code":200,
"data":bookList,
})
}

最新文章

  1. 封装jQuery Validate扩展验证方法
  2. Android中的进程与线程
  3. javascript优化--11模式(设计模式)02
  4. EF常用查询写法
  5. Asp.net MVC4 网站发布
  6. SerializableMaplist传递数据
  7. program_options禁止命令行短参数
  8. 笔记之Cyclone IV第一卷第三章器件中的存储器模块
  9. Facebook开源的基于SQL的操作系统检测和监控框架:osquery daemon详解
  10. :nth-child(n)
  11. xx星空面试题
  12. Python基础-day01
  13. 【UOJ】#49.铀仓库
  14. 013 jquery中关于表格行的增删问题
  15. Mysql 获取当天,昨天,本周,本月,上周,上月的起始时间
  16. VMware与Hyper-V
  17. #001 如何组织JS代码
  18. NetworkX 使用(二)
  19. JAVA中有一个特殊的类: Object
  20. C语言编译器和IDE的选择

热门文章

  1. JVM内存模型不再是秘密
  2. IDM下载度盘文件
  3. Java知识系统回顾整理01基础03变量07final关键字
  4. 【随笔---转载】xip.io
  5. 2-Java面试-面向对象
  6. Oracle 存储过程解锁及表解锁和停止执行
  7. ubuntu20 使用命令安装 mongodb
  8. id+is+深浅co&#39;p&#39;y
  9. ThreadLocal什么时候会出现OOM的情况?为什么?
  10. 从源码的角度解析Mybatis的会话机制