好久未更新,最近的go项目需要后端提供下载excel的二进制文件流,写完前端调用时出现跨域请求错误问题,就此记录一下错误和解决方式以及部分代码
一、问题暴露
二、问题解决
我的问题是:接口请求拦截未返回json数据的接口没有放开
//把不返回json数据的router路径添加到此处
var Fileter = []string{
"/admin/v1/orders_down",
}
func CommonReturn(c *gin.Context) {
c.Next()
Uri := c.Request.URL.Path
if ok := utils.IsExistString(Uri, Fileter); ok {
return
}
if c.Writer.Status() == 404 {
c.Abort()
return
}
data := ctl.GetData(c)
if len(data.Msg) == 0 {
ctl.GetErrMsg(data, data.Ret)
}
//统一返回数据
c.JSON(200, data)
}
var originMap map[string]int
func init() {
var url = conf.GetString("originUrl")
originMap = map[string]int{
"maniujk-app": 1,
"mgmt" + url: 1,
"agent" + url: 1,
"member" + url: 1,
"vfqq" + url: 1,
}
}
func Core() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,Tgt")
//c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, PATCH, DELETE")
c.Header("Access-Control-Allow-Methods", "POST, GET")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
c.Header("Access-Control-Allow-Credentials", "true")
// 放行所有OPTIONS方法,因为有的模板是要请求两次的
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
// 处理请求
c.Next()
}
}
ps:还有一种可能性参考
/*
下方这种方式应对处理 这种bug:http: wrote more than the declared Content-Length
*/
//extraHeaders := map[string]string{
// "Content-Disposition": fmt.Sprintf(`attachment; filename="%s"`, "保险箱"),
//}
//c.DataFromReader(http.StatusOK, int64(contentLength), "application/xlsx", excel, extraHeaders)
三、相关代码
excel生成公共方法,可放在util工具类中
// DataToExcel 数据导出excel,titleList为表头数组 dataList里面的对象为指针
func DataToExcel(titleList []string, dataList []interface{}) *bytes.Reader {
// 生成一个新的文件
file := xlsx.NewFile()
// 添加sheet页
sheet, _ := file.AddSheet("Sheet1")
// 插入表头
titleRow := sheet.AddRow()
for _, v := range titleList {
cell := titleRow.AddCell()
cell.Value = v
cell.GetStyle().Font.Color = "00FF0000"
}
// 插入内容
for _, v := range dataList {
row := sheet.AddRow()
row.WriteStruct(v, -1)
}
var buffer bytes.Buffer
_ = file.Write(&buffer)
content := bytes.NewReader(buffer.Bytes())
//返回一个二进制文件流
return content
}
controller调用
func DownExcel(c *gin.Context) {
data := ctl.NewSetData(c)
orderList := m_order.OrderList{}
err := c.ShouldBindJSON(&orderList)
if err != nil {
data.Ret = ctl.ErrorArgs
return
}
titleList := []string{"会员ID", "会员有效期", "开通时间", "上次登录时间"}
var dataList []interface{}
for _,v:=range orderList.OrderList{
dataList = append(dataList,v)
}
//返回excel 二进制文件流
excel := utils.DataToExcel(titleList, dataList)
var fileName ="文件名称"
fileName = fmt.Sprintf("%s.xlsx", fileName)
c.Writer.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName))
c.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
http.ServeContent(c.Writer, c.Request, fileName, time.Now(), excel)
return
}
db中需要接收数据
// 运营查看的数据
type ProStatus struct {
UserId string `json:"user_id" xorm:"comment('用户id') VARCHAR(128)"`
PackageName string `json:"package_name" xorm:"comment('套餐名') VARCHAR(128)"`
CreatedTime int64 `json:"created_time" xorm:"comment('创建时间')"`
LastLoginTime int64 `json:"last_login_time"`
}
//用于接收前端导入excel 数据
type OrderList struct {
OrderList []*ProStatus `json:"order_list"`
}