- Add
1. 增加自定义短链接口,前端支持自定义短链 2. 短链请求时自动续期1D,每天允许续期1次
This commit is contained in:
parent
effc71cec0
commit
cc716e3074
64
main.go
64
main.go
@ -35,6 +35,11 @@ const defaultPort int = 8002
|
|||||||
const defaultExpire = 90
|
const defaultExpire = 90
|
||||||
const defaultRedisConfig = "127.0.0.1:6379"
|
const defaultRedisConfig = "127.0.0.1:6379"
|
||||||
|
|
||||||
|
const defaultLockPrefix = "myurls:lock:"
|
||||||
|
const defaultRenewal = 1
|
||||||
|
|
||||||
|
const secondsPerDay = 24 * 3600
|
||||||
|
|
||||||
var redisPool *redis.Pool
|
var redisPool *redis.Pool
|
||||||
var redisPoolConfig *redisPoolConf
|
var redisPoolConfig *redisPoolConf
|
||||||
var redisClient redis.Conn
|
var redisClient redis.Conn
|
||||||
@ -83,6 +88,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
longUrl := context.PostForm("longUrl")
|
longUrl := context.PostForm("longUrl")
|
||||||
|
shortKey := context.PostForm("shortKey")
|
||||||
if longUrl == "" {
|
if longUrl == "" {
|
||||||
res.Message = "longUrl为空"
|
res.Message = "longUrl为空"
|
||||||
context.JSON(400, *res)
|
context.JSON(400, *res)
|
||||||
@ -91,25 +97,34 @@ func main() {
|
|||||||
|
|
||||||
_longUrl, _ := base64.StdEncoding.DecodeString(longUrl)
|
_longUrl, _ := base64.StdEncoding.DecodeString(longUrl)
|
||||||
longUrl = string(_longUrl)
|
longUrl = string(_longUrl)
|
||||||
|
|
||||||
shortKey := longToShort(longUrl, *ttl*24*3600)
|
|
||||||
if shortKey == "" {
|
|
||||||
res.Code = 0
|
|
||||||
res.Message = "短链接生成失败"
|
|
||||||
context.JSON(500, *res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println(longUrl, shortKey)
|
|
||||||
|
|
||||||
res.LongUrl = longUrl
|
res.LongUrl = longUrl
|
||||||
|
|
||||||
|
// 根据有没有填写 short key,分别执行
|
||||||
|
if shortKey != "" {
|
||||||
|
redisClient := redisPool.Get()
|
||||||
|
|
||||||
|
// 检测短链是否已存在
|
||||||
|
_exists, _ := redis.String(redisClient.Do("get", shortKey))
|
||||||
|
if _exists != "" && _exists != longUrl {
|
||||||
|
res.Message = "短链接已存在,请更换key"
|
||||||
|
context.JSON(400, *res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存储
|
||||||
|
_, _ = redisClient.Do("set", shortKey, longUrl)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
shortKey = longToShort(longUrl, *ttl*secondsPerDay)
|
||||||
|
}
|
||||||
|
|
||||||
protocol := "http://"
|
protocol := "http://"
|
||||||
if *https != 0 {
|
if *https != 0 {
|
||||||
protocol = "https://"
|
protocol = "https://"
|
||||||
}
|
}
|
||||||
res.ShortUrl = protocol + *domain + "/" + shortKey
|
res.ShortUrl = protocol + *domain + "/" + shortKey
|
||||||
|
|
||||||
|
context.Header("Access-Control-Allow-Origin", "*")
|
||||||
context.JSON(200, *res)
|
context.JSON(200, *res)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -133,6 +148,12 @@ func shortToLong(shortKey string) string {
|
|||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
|
|
||||||
longUrl, _ := redis.String(redisClient.Do("get", shortKey))
|
longUrl, _ := redis.String(redisClient.Do("get", shortKey))
|
||||||
|
|
||||||
|
// 获取到长链接后,续命1天。每天仅允许续命1次。
|
||||||
|
if longUrl != "" {
|
||||||
|
renew(shortKey)
|
||||||
|
}
|
||||||
|
|
||||||
return longUrl
|
return longUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +174,7 @@ func longToShort(longUrl string, ttl int) string {
|
|||||||
// 重试三次
|
// 重试三次
|
||||||
var shortKey string
|
var shortKey string
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
shortKey = generate(6)
|
shortKey = generate(7)
|
||||||
|
|
||||||
_existsLongUrl, _ := redis.String(redisClient.Do("get", shortKey))
|
_existsLongUrl, _ := redis.String(redisClient.Do("get", shortKey))
|
||||||
if _existsLongUrl == "" {
|
if _existsLongUrl == "" {
|
||||||
@ -165,7 +186,7 @@ func longToShort(longUrl string, ttl int) string {
|
|||||||
_, _ = redisClient.Do("mset", shortKey, longUrl, longUrl, shortKey)
|
_, _ = redisClient.Do("mset", shortKey, longUrl, longUrl, shortKey)
|
||||||
|
|
||||||
_, _ = redisClient.Do("expire", shortKey, ttl)
|
_, _ = redisClient.Do("expire", shortKey, ttl)
|
||||||
_, _ = redisClient.Do("expire", longUrl, ttl)
|
_, _ = redisClient.Do("expire", longUrl, secondsPerDay)
|
||||||
}
|
}
|
||||||
|
|
||||||
return shortKey
|
return shortKey
|
||||||
@ -205,3 +226,20 @@ func initRedisPool() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func renew(shortKey string) {
|
||||||
|
redisClient = redisPool.Get()
|
||||||
|
defer redisClient.Close()
|
||||||
|
|
||||||
|
// 加锁
|
||||||
|
lockKey := defaultLockPrefix + shortKey
|
||||||
|
lock, _ := redis.Int(redisClient.Do("setnx", lockKey, 1))
|
||||||
|
if lock == 1 {
|
||||||
|
// 设置锁过期时间
|
||||||
|
_, _ = redisClient.Do("expire", lockKey, defaultRenewal*secondsPerDay)
|
||||||
|
|
||||||
|
// 续命
|
||||||
|
ttl, _ := redis.Int(redisClient.Do("ttl", shortKey))
|
||||||
|
_, _ = redisClient.Do("expire", shortKey, ttl+defaultRenewal*secondsPerDay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
<el-input ref="long" v-model="longUrl" size="medium" @keyup.enter.native="enterToDoShort">
|
<el-input ref="long" v-model="longUrl" size="medium" @keyup.enter.native="enterToDoShort">
|
||||||
<el-button slot="append" icon="el-icon-magic-stick" @click="doShort" :loading="loading"></el-button>
|
<el-button slot="append" icon="el-icon-magic-stick" @click="doShort" :loading="loading"></el-button>
|
||||||
</el-input>
|
</el-input>
|
||||||
<el-input class="copy-content" v-model="shortUrl" size="medium" readonly v-if="shortUrl !== ''">
|
<el-input ref="shortUrl" @dblclick.native="changeDisableStatus" class="copy-content" v-model="shortUrl" size="medium">
|
||||||
<el-button slot="append" v-clipboard:copy="shortUrl" v-clipboard:success="onCopy" ref="copy-btn"
|
<el-button slot="append" v-clipboard:copy="shortUrl" v-clipboard:success="onCopy" ref="copy-btn"
|
||||||
icon="el-icon-document-copy"></el-button>
|
icon="el-icon-document-copy"></el-button>
|
||||||
</el-input>
|
</el-input>
|
||||||
@ -71,6 +71,7 @@
|
|||||||
|
|
||||||
let data = new FormData();
|
let data = new FormData();
|
||||||
data.append("longUrl", btoa(this.longUrl));
|
data.append("longUrl", btoa(this.longUrl));
|
||||||
|
data.append("shortKey", this.shortUrl.indexOf('http') < 0 ? this.shortUrl : '');
|
||||||
axios.post(backend + '/short', data, {
|
axios.post(backend + '/short', data, {
|
||||||
header: {
|
header: {
|
||||||
"Content-Type": "application/form-data; charset=utf-8"
|
"Content-Type": "application/form-data; charset=utf-8"
|
||||||
@ -80,6 +81,7 @@
|
|||||||
if (res.data.Code === 1 && res.data.ShortUrl !== "") {
|
if (res.data.Code === 1 && res.data.ShortUrl !== "") {
|
||||||
this.shortUrl = res.data.ShortUrl;
|
this.shortUrl = res.data.ShortUrl;
|
||||||
this.$copyText(this.shortUrl)
|
this.$copyText(this.shortUrl)
|
||||||
|
this.$refs.shortUrl.disabled = true
|
||||||
this.$message.success("短链接已复制到剪贴板");
|
this.$message.success("短链接已复制到剪贴板");
|
||||||
} else {
|
} else {
|
||||||
this.$message.error("短链接获取失败:" + res.data.Message);
|
this.$message.error("短链接获取失败:" + res.data.Message);
|
||||||
@ -119,6 +121,9 @@
|
|||||||
onCopy() {
|
onCopy() {
|
||||||
this.$message.success("Copied!");
|
this.$message.success("Copied!");
|
||||||
},
|
},
|
||||||
|
changeDisableStatus(event) {
|
||||||
|
this.$refs.shortUrl.disabled = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user