c mysql短连接_Go语言写的一个短网址服务

597489741d5354d74177862ac21d0f56.png

“缩址,又称短址、短网址、网址缩短、缩短网址、URL缩短等,指的是一种互联网上的技术与服务。此服务可以提供一个非常短小的URL以代替原来的可能较长的URL,将长的URL地址缩短。

用户访问缩短后的URL时,通常将会重定向到原来的URL。”

– Wikipedia

虽然短网址早已不再那么受广泛关注。但是不妨拿来练手。

根据公开可以搜索到的资料,短网址一般是将一个ID转换到一串字母,生成短的网址用于传播,实际访问会重定向到原网址。如上所述。

那么使用Go来写这个有什么优势呢,优势之一当然是,Go部署简单,只需要copy执行文件即可。执行速度也快,甚至连HTTP服务器都不需要。

下边就边写边说明。

12345678910111213141516package mainimport ("fmt""strings""time""net/http""database/sql""github.com/gin-gonic/gin""github.com/garyburd/redigo/redis"_ "github.com/go-sql-driver/mysql""github.com/speps/go-hashids")定义hashid包需要的salt,即生成字符串的最短位数。

12345const (hdSalt        = "mysalt"hdMinLength   = 5defaultDomain = "http://localhost:8000/")定义redis和MySQL的配置信息

123456789101112var (RedisClient *redis.PoolRedisHost   = "127.0.0.1:6379"RedisDb     = 0RedisPwd    = ""db      *sql.DBDB_HOST = "tcp(127.0.0.1:3306)"DB_NAME = "short"DB_USER = "root"DB_PASS = "")

main函数,首先连接redis和MySQL。定义如下路由:访问首页

访问hash

访问短网址信息页

生成短网址接口

熟悉的朋友应该都知道,访问短网址服务的首页一般会跳转到一个固定的网址,比如渣浪微博会跳转到微博首页,Twitter则是给出“Twitter uses the t.co domain as part of a service to protect users from harmful activity”的提示。这里我们也让它跳转到一个指定的网页。

最后,以8080端口运行,实际线上会使用80端口,可以自行修改。

1234567891011121314151617func main() {initRedis()initMysql()gin.SetMode(gin.DebugMode)r := gin.Default()r.GET("/", func(c *gin.Context) {//http code can be StatusFound or StatusMovedPermanently c.Redirect(http.StatusFound, defaultDomain)})r.GET("/:hash", expandUrl)r.GET("/:hash/info", expandUrlApi)r.POST("/short", shortUrl)r.Run(":8000")}

连接redis和MySQL

12345678910111213141516171819202122232425262728func initRedis() {// 建立连接池RedisClient = &redis.Pool{MaxIdle:     1,MaxActive:   10,IdleTimeout: 180 * time.Second,Dial: func() (redis.Conn, error) {c, err := redis.Dial("tcp", RedisHost)if err != nil {return nil, err}if _, err := c.Do("AUTH", RedisPwd); err != nil {c.Close()return nil, err}c.Do("SELECT", RedisDb)return c, nil},}}func initMysql() {dsn := DB_USER + ":" + DB_PASS + "@" + DB_HOST + "/" + DB_NAME + "?charset=utf8"db, _ = sql.Open("mysql", dsn)db.SetMaxOpenConns(5)db.SetMaxIdleConns(20)db.Ping()}

生成短网址的接口函数。

根据传入的URL参数,进行简单的验证后,写入数据库。根据写入后生成的ID,再生成一个字符串,输出短链接,然后返回给调用方。

1234567891011121314151617181920212223func shortUrl(c *gin.Context) {longUrl := c.PostForm("url")if longUrl == "" {c.JSON(200, gin.H{"status":  500,"message": "请传入网址",})return}if !strings.HasPrefix(longUrl, "http") {longUrl = "http://" + longUrl}if hash, ok := insert(longUrl); ok {c.JSON(200, gin.H{"status":  200,"message": "ok","short":   defaultDomain + hash,})}}

根据HASH解析并跳转到对应的长URL,不存在则跳转到默认地址

1234567891011func expandUrl(c *gin.Context) {hash := c.Param("hash")if url, ok := findByHash(hash); ok {c.Redirect(http.StatusMovedPermanently, url)}// 注意:// 实际中,此应用的运行域名可能与默认域名不同,如a.com运行此程序,默认域名为b.com// 当访问一个不存在的HASH或a.com时,可以跳转到任意域名,即defaultDomainc.Redirect(http.StatusMovedPermanently, defaultDomain)}

根据HASH在redis中查找并返回结果,不存在则返回404状态

123456789101112131415161718func expandUrlApi(c *gin.Context) {hash := c.Param("hash")if url, ok := findByHash(hash); ok {c.JSON(200, gin.H{"status":  200,"message": "ok","data":    url,})return}// 此处可以尝试在MySQL中再次查询c.JSON(200, gin.H{"status":  404,"message": "url of hash is not exist",})}

将ID转换成对应的HASH值,hdSalt与hdMinLength 会影响生成结果,确定后不要改动

12345678910func shortenURL(id int) string {hd := hashids.NewData()hd.Salt = hdSalthd.MinLength = hdMinLengthh := hashids.NewWithData(hd)e, _ := h.Encode([]int{id})return e}

根据HASH解析出对应的ID值, hdSalt与hdMinLength 会影响生成结果,确定后不要改动

12345678910func expand(hash string) int {hd := hashids.NewData()hd.Salt = hdSalthd.MinLength = hdMinLengthh := hashids.NewWithData(hd)d, _ := h.DecodeWithError(hash)return d[0]}

数据库中根据ID查找

123456789func find(id int) (string, bool) {var url stringerr := db.QueryRow("SELECT url FROM url WHERE id = ?", id).Scan(&url)if err == nil {return url, true} else {return "", false}}

在redis中根据HASH查找

1234567891011121314151617func findByHash(h string) (string, bool) {rc := RedisClient.Get()defer rc.Close()url, _ := redis.String(rc.Do("GET", "URL:"+h))if url != "" {return url, true}id := expand(h)if urldb, ok := find(id); ok {return urldb, true}return "", false}

将长网址插入到数据库中,并把返回的ID生成HASH和长网址存入redis

123456789101112131415func insert(url string) (string, bool) {stmt, _ := db.Prepare(`INSERT INTO url (url) values (?)`)res, err := stmt.Exec(url)checkErr(err)id, _ := res.LastInsertId()rc := RedisClient.Get()defer rc.Close()hash := shortenURL(int(id))rc.Do("SET", "URL:"+hash, url)return hash, true}

打印方法,和检查错误的方法

123456789func Log(v ...interface{}) {fmt.Println(v...)}func checkErr(err error) {if err != nil {panic(err)}}

有些地方还需修改,就算是抛砖引玉吧。

Github地址 : shortme

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值