内容目录
Ant Design Vue
是一套优秀的前端开发框架,作为一个后端程序员都对他喜爱有加,后端程序要想很好的使用这个框架,有一些基本的工作要做。这里我使用Go
语言作为后端程序,并且使用了Gin
作为web框架。
浏览器跨域问题
这里要允许浏览器的跨域,浏览器在涉及到跨域请求的时候会先发送一个OPTION类型的请求,所以我们要及时的响应这种类型的请求(直接响应200状态码就好),并且设置好响应头。
// 浏览器跨域
func cors(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, Access-Token")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
c.Header("X-Frame-cors", "DENY")
c.Header("X-Content-Type-cors", "nosniff")
c.Header("X-XSS-Protection", "1; mode=block")
if c.Request.TLS != nil {
c.Header("Strict-Transport-Security", "max-age=31536000")
}
if c.Request.Method == http.MethodOptions {
c.AbortWithStatus(http.StatusOK)
return
}
c.Next()
}
// 然后在对应的接口下进行调用,比如这里的登录接口
auth := r.Group("/auth")
auth .Use(cors)
{
auth.POST("/login", login)
}
请注意,这里有一个
token问题
Ant Design Vue
在登录成功后要求获得token
,后面的每次请求都会带上这个token,并且服务端要及时的去验证这些token的有效性。
如何生成token
现在广泛使用的是jwt token.这里我们使用github.com/dgrijalva/jwt-go
这个开源库。
package router
import (
"errors"
"github.com/dgrijalva/jwt-go"
"time"
)
// token加密key
var tokenSigningKey = []byte("my-token")
var TokenInvalid = errors.New("token is invalid")
// 这里我让token携带两个参数,Channel 和 ChannelId
type AdsClaims struct {
ChannelId int64 `json:"channelId"`
Channel string `json:"channel"`
jwt.StandardClaims
}
// 生成token,这里token的有效期是2小时
func signToken(id int64, channel string) (string, error) {
claims := AdsClaims{
ChannelId: id,
Channel: channel,
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(time.Hour * 2).Unix(),
Issuer: "test",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(tokenSigningKey)
}
// 解析token,并且判断token是否有效
func parseToken(tokenString string) (*AdsClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &AdsClaims{}, func(token *jwt.Token) (interface{}, error) {
return tokenSigningKey, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*AdsClaims); ok && token.Valid {
return claims, nil
}
return nil, TokenInvalid
}
如何使用token
token 用在两个地方,登录和校验:
func login(c *gin.Context) {
var u db.Channel
if c.BindJSON(&u) != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
if msg := u.Login(); msg != "" {
c.JSON(http.StatusUnauthorized, gin.H{"message": msg})
} else {
token, err := signToken(u.Id, u.Username)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
// 登录成功,响应token出去
c.JSON(http.StatusOK, build(gin.H{
"id": u.Id,
"companyName": u.CompanyName,
"token": token,
}))
}
}
一般来说我们除了登录,注册等一些方法外都需要校验token.比如如下配置
api := r.Group("/api")
api.Use(cors,authCheck())
{
admin.GET("/user/info", userInfo)
admin.GET("/user/list", userList)
}
func authCheck() gin.HandlerFunc {
return func(c *gin.Context) {
// Parse the json web token.
if claims, err := parseRequest(c); err != nil {
c.JSON(http.StatusUnauthorized, err)
c.Abort()
return
} else {
// 把channelId放入到context中,后续环节可以使用
c.Set(config.ChannelIdKey, claims.ChannelId)
c.Set(config.ChannelKey, claims.Channel)
}
c.Next()
}
}
func parseRequest(c *gin.Context) (*AdsClaims, error) {
accessToken := c.Request.Header.Get("Access-Token")
if len(accessToken) == 0 {
return nil, ErrMissingHeader
}
return parseToken(accessToken)
}
这里就保证了每次请求都会优先校验token,如果校验不通过或者token已过期,都会直接响应Unauthorized状态码(401)
导出Excel文件
有些报表需要导出Excel文件,这里前后端都要请求重写的哦!请注意
先说后端:
package router
import (
"github.com/360EntSecGroup-Skylar/excelize"
"github.com/gin-gonic/gin"
)
func excelExport(c *gin.Context) {
// 生成Excel文件
f := excelize.NewFile()
// Create a new sheet.
index := f.NewSheet("Sheet2")
// Set value of a cell.
f.SetCellValue("Sheet2", "A2", "Hello world.")
f.SetCellValue("Sheet1", "B2", 100)
// Set active sheet of the workbook.
f.SetActiveSheet(index)
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", "attachment; filename=Book1.xlsx")
c.Header("Content-Transfer-Encoding", "binary")
_ = f.Write(c.Writer)
}
再说前端:一定要设置好responseType:
'blob'
export function excelExport (parameter) {
return axios({
url: '/api/excel_export',
method: 'post',
data: parameter,
responseType: 'blob'
})
}
不仅如此,前端也要实现自己的下载逻辑:
excelExport () {
var tm = this.queryParam.tm.format('YYYY-MM-DD')
return reportLog({
tm,
export: true
}).then(data => {
const url = window.URL.createObjectURL(new Blob([data]))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', `Book1.xlsx`)
document.body.appendChild(link)
link.click()
}).catch(err => {
console.log(err)
})
}
}
如有问题,欢迎浏览讨论~
0 条评论
撰写评论