相关文章:
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-1.工具和本地环境
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-2.启动项目
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-3.接收json数据
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-4.连接mongodb数据库
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-5.跨域并跨域传输数据
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-6.GO语言做通用CRUD接口-1
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-7.GO语言做通用CRUD接口-2
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-8.模型的关联——无限层级分类
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-9.管理员及登录注册功能的实现
技能学习:学习使用golang(gin框架) + vue.js,开发前端全栈网站-10.生产环境编译
跨域指的是浏览器不能执行其他网站或域名下的脚本。之所以形成跨域,是因为浏览器的同源策略造成的,是浏览器对javascript程序做的安全限制,现在所有支持JavaScript 的浏览器都会使用这个策略。
在本次项目就用到前后端分离,前后端不在同域(这里的同域指的是同一协议,同一域名,同一端口),那么,它们之间相互通信如何解决呢?
首先将前端内容做出。
大家对npm和vue不熟悉的话可以参考我之前的文章
技能学习:学习使用Node.js +
Vue.js,开发前端全栈网站-2.启动项目
技能学习:学习使用Node.js +
Vue.js,开发前端全栈网站-3.element-ui和路由的安装和使用
里面介绍了相关启动项目的包和element前端样式框架等。
我完全按这两篇文章进行admin端制作,本篇文章我就不做演示了。最终效果:
到此,我们已经知道如何使用vue搭建页面,下面改动我们做好的页面:
(1)制作新建分类页面CategorySet.vue:
<template>
<div>
<h1>创建分类</h1>
<el-form label-width="80px" style="margin-top:20px;" @submit.native.prevent="save">
<!-- submit事件中使用提交方法save,native是找到js原生表单,prevent是指阻止提交时默认跳转页面 -->
<el-form-item label="分类名">
<el-input v-model="model.name"></el-input>
<!-- 双向绑定model -->
</el-form-item>
<el-form-item>
<el-button type="primary" native-type="submit">保存</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data(){
return {
model: {}
}
},
methods: {
save(){
//这里放axios方法,用来提交数据
}
}
}
</script>
(2)引入新建分类页面:
(3)将新建分类页面的路由设置在左侧导航栏:
此时创建分类页面就可以显示,可以当作表单进行上传功能使用。
终端安装axios:
cd admin
npm i axios
此时安装axios完成。
为了代码的清晰,避免main.js混乱,专门在main.js同级给axios创建一个js文件存放axios的接口,名为http.js,后在main.js引入。
引入axios包,同时创建一个axios实例,发送地址为服务器端server的admin/api接口下,此处直译为admin后台的api接口,稍后在服务端创建此地址。
http.js:
// 引入axios
import axios from 'axios'
// 创建axios实例,添加api路径
const http = axios.create({
baseURL:'http://localhost:3000/admin'
})
// 将文件变量导出,导出到main.js
export default http
main.js:
此时http实例(也就是axios实例)已经创建好,并已放入vue实例中,在我们调用后端接口时只要使用this.$http
(或Vue.$http
)就可使用axios。
此时,回到CategorySet.vue页面,使用POST方法写提交数据的方法:
之前我们已经在server端创建好接口,先进行下测试:
(1)补全接口,使用异步请求
// 使用async..await异步请求方法
async save(){
// 这里放axios方法,用来提交数据
// 接口调用之前写好的后台find_all查询接口进行测试接口连接
const res = await this.$http.post('/find_all')
console.log(res)
}
(2)本地开启后台服务:
本地环境中需要开启server端项目,才可进行访问。
可以看到server端的find_all接口,但是我们发现之前定义的路由地址是http://localhost:3000/mongo/find_all,所以需要改一下现在的axios实例:
(2)点击保存按钮进行接口的调用:
请求报错,CORS error。
跨域问题,做了这么多,终于到了本篇文章的重点,跨域操作。
跨域操作,简单来说就是设置接口的请求头:
func(c *gin.Context) {
method := c.Request.Method
c.Header("Access-Control-Allow-Origin", "*") // 允许访问所有域,可以换成具体url,注意仅具体url才能带cookie信息
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token") //header的类型
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") //允许请求方法
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") //设置为true,允许ajax异步请求带cookie信息
//放行所有OPTIONS方法
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
}
如何在go接口路由中使用请求头呢?先将整页代码贴出:
package db
import(
"github.com/gin-gonic/gin"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"net/http"
)
// 定义结构
type user struct{
Username string `json:"username"`
Password string `json:"password"`
}
// 插入数据
func insert(ctx *gin.Context){
// 连接mongodb服务
url := "mongodb://127.0.0.1"
// 设置数据库一致性模式
// 连接数据库操作,该操作赋值给session
// err值必写,用于错误处理
session, err := mgo.Dial(url)
// 后边程序执行的err与go程序比对,若有错误则返回错误内容
if err != nil {
panic(err)
}else{
// 若没有错误,则在页面返回字符串,显示插入成功
ctx.String(http.StatusOK, "插入成功")
}
// defer用法大家自行百度,我解释不清
defer session.Close()
// 设置数据库一致性模式,就当作打开数据库
session.SetMode(mgo.Monotonic, true)
// 找到某数据库下的某数据表
c := session.DB("db_go").C("user")
// 将insert状态传值给err
err = c.Insert(&user{"admin", "123456"},&user{"Johnson", "Johnson"})
}
// 查询数据
func find(ctx *gin.Context){
url := "mongodb://127.0.0.1"
session, err := mgo.Dial(url)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("db_go").C("user")
// 定义查询结构,根据上方定义的结构查询usr
usr := user{}
// 查找数据
err = c.Find(bson.M{"username": "Johnson"}).One(&usr)
ctx.JSON(http.StatusOK, usr)
}
// 查询全部数据
func findAll(ctx *gin.Context){
url := "mongodb://127.0.0.1"
session, err := mgo.Dial(url)
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("db_go").C("user")
// 查找全部
usrs := make([]user, 10)
// 查找全部
err = c.Find(nil).All(&usrs)
ctx.JSON(http.StatusOK, usrs)
}
// 删除数据
func delete(ctx *gin.Context){
url := "mongodb://127.0.0.1"
session, err := mgo.Dial(url)
if err != nil {
panic(err)
}else{
ctx.String(http.StatusOK, "删除成功")
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("db_go").C("user")
err = c.Remove(bson.M{"username": "Johnson"})
}
// 修改数据
func update(ctx *gin.Context){
url := "mongodb://127.0.0.1"
session, err := mgo.Dial(url)
if err != nil {
panic(err)
}else{
ctx.String(http.StatusOK, "修改成功")
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
c := session.DB("db_go").C("user")
err = c.Update(bson.M{"username": "Johnson"},bson.M{"$set": bson.M{"password": "123456"}})
}
// 处理跨域请求,将跨域请求函数作为中间件处理
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
c.Header("Access-Control-Allow-Origin", "*") // 允许访问所有域,可以换成具体url,注意仅具体url才能带cookie信息
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token") //header的类型
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") //允许请求方法
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") //设置为true,允许ajax异步请求带cookie信息
//放行所有OPTIONS方法
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
// 处理请求
c.Next()
}
}
// 配置路由
func Main(e *gin.Engine) {
// 全局使用中间件
e.Use(Cors())
// 定义路由,调用接口函数
e.GET("/mongo/insert", insert)
// 定义json函数接口
e.GET("/mongo/find", find)
// 定义json结构体函数接口
e.POST("/mongo/find_all", findAll)
// 定义json结构体函数接口
e.GET("/mongo/delete", delete)
// 定义json结构体函数接口
e.GET("/mongo/update", update)
// 将路由信息return回调
// return r
}
昨晚跨域工作后,由于我们传输方法用的是post(),所以后端路由接口也要改为POST方法:
此时,跨域操作已完成,重新编译执行server端:
在admin端测试接口:
接口调用成功,点击查看调用的数据:
成功查询成功。同时我们console的res也成功查询出来了:
(1)admin端修改调用接口的方法:
async save(){
// 这里放axios方法,用来提交数据
// 接口调用之前写好的后台insert插入接口进行测试接口连接
// 并传值
const res = await this.$http.post('/insert', this.model)
console.log(res)
// 提示信息,使用vue中自带的$message实例
this.$message({
type: 'success',
message: '保存成功'
})
}
此时如果点击保存按钮就会带值传输到后端。
(2)修改server端插入数据接口:
// 插入数据
func insert(ctx *gin.Context){
// 连接mongodb服务
url := "mongodb://127.0.0.1"
// 设置数据库一致性模式
// 连接数据库操作,该操作赋值给session
// err值必写,用于错误处理
session, err := mgo.Dial(url)
// 后边程序执行的err与go程序比对,若有错误则返回错误内容
if err != nil {
panic(err)
}else{
// 若没有错误,则在页面返回字符串,显示插入成功
ctx.String(http.StatusOK, "插入成功")
}
// defer用法大家自行百度,我解释不清
defer session.Close()
// 设置数据库一致性模式,就当作打开数据库
session.SetMode(mgo.Monotonic, true)
// 找到某数据库下的某数据表
c := session.DB("db_go").C("user")
// 接收传值,将传值添加到上方定义的数据表结构中
var form user
// 如果传值格式不符合上方定义的结构,则返回错误信息
if err := ctx.Bind(&form); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 此时&form就继承了上方定义的结构格式
// 插入数据,并将insert状态传值给err
err = c.Insert(&form)
}
(3)将之前定义的接口路由改为POST方法:
编译测试,重启server端:
在admin端页面输入信息,并点击按钮:
数据的传值与接收没什么问题,虽然过程成功,但是我目前有一个很大的错误:
所以我们需要查询一下这个表的所有数据,看到底有没有成功插入词条数据。
由于我们的接口方法改成了POST传输,所以在网页中已经无法调用这个接口了:
所以我们需要使用第三方测试工具Postman,进行调用接口查询。
(1)下载安装Postman
下载地址:https://www.postman.com/downloads/
下载好双击安装即可。
(2)使用Postman
使用前需要先登录,登录完成到此界面:
新建项目:
选择HTTP Request:
选择请求方式,并输入路由地址:
点击Send后查询到数据:
果然,跟我想的一样,并没有传入成功。看来之前的错误审核操作只能返回接口的调用状态,并不能检查出结构和名字的错误:
我们根据CategorySet新建分类功能,新建一个数据结构,并新建插入数据接口函数。
(1)新定义结构:
(2)新定义插入数据接口函数:
(3)添加新的插入接口:
路由的定义与真实路径无关,只要访问到该路径即可调用接口函数。
(4)server端编译执行测试:
(5)前端传输数据路由改成对应路径:
前端页面进行测试:
显示成功,我们需要查询是否成功。
(6)由于我们将数据插入到了新的表category中,所以我们同样需要制作category表的查询接口函数:
同时下方引入接口路由:
重新编译运行:
此时,使用Postman访问路由地址进行查询:
可以,没问题,很牛*。
到此,跨域和跨域传输数据,也就是前后端分离的数据传输就完成了,这也是一个动态网站功能进行完善的基础与雏形。
(1)本篇文章到这里,我们还是继承了上篇文章的问题,我们目前每需要调用一个接口,就需要新建一个接口函数,太烦了,太惨了。
所以下篇文章我们一起研究CRUD通用接口,让所有数据表只使用固定的几个增删改查接口。
(2)在CRUD接口完成后,我们再继续完善查找、删除、修改数据的接口(否则我们得多写好几个函数接口,写的越多大家学习过程就越乱)。
更多设计、功能的学习经验,大家也可以去我的公众号查看!
————