? ?本篇使用Vue2開(kāi)發(fā)前端,Go語(yǔ)言開(kāi)發(fā)服務(wù)端,使用nginx代理部署實(shí)現(xiàn)登錄頁(yè)面及其校驗(yàn)功能。
目錄
1.部署結(jié)構(gòu)
2.Vue2前端
2.1代碼結(jié)構(gòu)
2.1源碼
3.Go后臺(tái)服務(wù)
3.2代碼結(jié)構(gòu)
3.2?源碼
3.3單測(cè)效果
4.nginx
5.運(yùn)行效果
6.問(wèn)題總結(jié)
1.部署結(jié)構(gòu)
?
2.Vue2前端
2.1代碼結(jié)構(gòu)
2.1源碼
index.html
<!DOCTYPE html>
<html>
? <head>
? ? <meta charset="utf-8">
? ? <meta name="viewport" content="width=device-width,initial-scale=1.0">
? ? <title>demo</title>
? </head>
? <body>
? ? <div id="myapp"></div>
? ? <!-- built files will be auto injected -->
? </body>
</html>
src/App.vue
<template>
<div>
<router-view></router-view>
</div>
</template>
src/assets/css/reset.css
/* http://meyerweb.com/eric/tools/css/reset/?
? ?v2.0 | 20110126
? ?License: none (public domain)
*/html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,?
figure, figcaption, footer, header, hgroup,?
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
?? ?margin: 0;
?? ?padding: 0;
?? ?border: 0;
?? ?font-size: 100%;
?? ?font: inherit;
?? ?vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,?
footer, header, hgroup, menu, nav, section {
?? ?display: block;
}
body {
?? ?line-height: 1;
}
ol, ul {
?? ?list-style: none;
}
blockquote, q {
?? ?quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
?? ?content: '';
?? ?content: none;
}
table {
?? ?border-collapse: collapse;
?? ?border-spacing: 0;
}
src/components/Home.vue
<template>
<div id="YYYYYYYYYYY" class="hello">
<button @click="goLogin">登錄</button>
<el-button type="primary">你好</el-button>
<el-button type="info">你好</el-button>
<el-button type="danger">你好</el-button>
<el-button type="success">你好</el-button>
<el-tag> fsfsd dsd dsfv</el-tag>
<i class="fa fa-user"></i>
<i class="fa fa-users"></i>
</div>
</template><style lang="scss">
? ? .hello {
? ? ? ? background: yello;
? ? ? ? .el-button {
? ? ? ? ? ? color: red;
? ? ? ? }
? ? }
@import url('../assets/css/reset.css')
</style>
<script>
export default {
? methods: {
? ? goLogin () {
? ? ? this.$router.push('/login')
? ? }
? }
}
</script>
src/components/Login.vue
<template>
? <div class="login">
? ? <el-card class="box-card">
? ? ? ? <div slot="header" class="clearfix">
? ? ? ? ? ? <span>業(yè)務(wù)后臺(tái)管理系統(tǒng)</span>
? ? ? ? </div>? ? ? ? <el-form label-width="100px" :model="form" ref="form" :rules='rules'>
? ? ? ? ? ? <el-form-item label="用戶名" prop='username'>
? ? ? ? ? ? ? ? <el-input v-model="form.username"></el-input>
? ? ? ? ? ? </el-form-item>
? ? ? ? ? ? <el-form-item label="密碼" prop='password'>
? ? ? ? ? ? ? ? <el-input type='password' v-model="form.password"></el-input>
? ? ? ? ? ? </el-form-item>
? ? ? ? ? ? <el-form-item>
? ? ? ? ? ? ? ? <el-button type='primary' @click="login('form')">登錄</el-button>
? ? ? ? ? ? </el-form-item>
? ? ? ? </el-form>
? ? </el-card>
? </div>
</template>/*
原生AJAX和Axios在使用上存在一定的區(qū)別。Axios可以支持多種方式,包括瀏覽器環(huán)境、node環(huán)境,而AJAX則只能在瀏覽器環(huán)境中使用。
Axios還支持多種請(qǐng)求方式,包括GET、POST、PUT、DELETE等;而AJAX只能支持GET和POST方式發(fā)送請(qǐng)求。此外,Axios還可以攔截請(qǐng)求和響應(yīng)。
*/<script>
//登錄驗(yàn)證的封裝
import {nameRule, passRule} from '../utils/validate.js'import {setToken} from '@/utils/dealtoken.js'
export default {
? data () {
? ? return {
? ? ? ? form: {
? ? ? ? ? ? username: "",
? ? ? ? ? ? password: ""
? ? ? ? },
? ? ? ? rules: {
? ? ? ? ? ? username: [{validator: nameRule, required: true, trigger: "blur"}],
? ? ? ? ? ? password: [{validator: passRule, required: true, trigger: "blur"}]
? ? ? ? }
? ? }
? },
? methods: {
? ? login(form) {
? ? ? ? this.$refs[form].validate((valid) => {
? ? ? ? ? ? if (valid) {
? ? ? ? ? ? ? ? console.log(this.form)
? ? ? ? ? ? ? ? //this.$router.push('/home')
? ? ? ? ? ? ? ? //解決axios post請(qǐng)求 404 ?OPTIONS問(wèn)題
? ? ? ? ? ? ? ? const posthead = {
? ? ? ? ? ? ? ? ? ? headers: {
? ? ? ? ? ? ? ? ? ? 'Content-Type': 'text/plain;charset=utf-8',
? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? //withCredentials: 'same-origin'
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? this.axios.post('http://localhost:8282/login', JSON.stringify(this.form), posthead).then(res => {
? ? ? ? ? ? ? ? ? ? console.log(res)
? ? ? ? ? ? ? ? ? ? if (res.status === 200) {
? ? ? ? ? ? ? ? ? ? ? ? //localStorage.setItem('username', res.data.username)
? ? ? ? ? ? ? ? ? ? ? ? setToken('username', res.data.username)
? ? ? ? ? ? ? ? ? ? ? ? this.$message({message: res.data, type: 'success'})
? ? ? ? ? ? ? ? ? ? ? ? this.$router.push('/home')
? ? ? ? ? ? ? ? ? ? ? ? console.log("post mid")
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? })
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? console.error(this.form)
? ? ? ? ? ? }
? ? ? ? })
? ? }
? }
}
</script><style lang='scss'>
? ? .login {
? ? ? ? width: 100%;
? ? ? ? height: 100%;
? ? ? ? position: absolute;
? ? ? ? background: #409EFF;
? ? ? ? .box-card {
? ? ? ? ? ? width: 450px;
? ? ? ? ? ? margin: 200px auto;
? ? ? ? ? ? .el-card_header {
? ? ? ? ? ? ? ? font-size: 34px;
? ? ? ? ? ? }
? ? ? ? ? ? .el-button {
? ? ? ? ? ? ? ? width: 100%;
? ? ? ? ? ? }
? ? ? ? }
? ? }
</style>
src/main.js
import Vue from 'vue'
import App from './App'
import 'font-awesome/css/font-awesome.min.css'
import axios from 'axios'
import router from './router'// 掛載到原型就可以全局使用
Vue.prototype.axios = axiosimport ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
new Vue({
? router,
? render: h => h(App)
}).$mount('#myapp')
src/router/index.js
import Vue from 'vue'
import Home from '@/components/Home'
import VueRouter from 'vue-router'Vue.use(VueRouter)
const routes = [
? { path: '/', redirect: '/login', component: () => import('@/components/Login') },
? { path: '/login', name: 'Login', component: () => import('@/components/Login') },
? { path: '/home', component: Home },
? { path: '*', component: Home }
]
export default new VueRouter({
? mode: 'history',
? routes: routes
})
src/utils/validate.js
// Token的封裝 Token存放在localStorage
export function setToken(tokenkey, token) {
? ? return localStorage.setItem(tokenkey, token)
}export function getToken(tokenkey) {
? ? return localStorage.getItem(tokenkey)
}export function removeToken(tokenkey) {
? ? return localStorage.removeItem(tokenkey)
}
src/utils/dealtoken.js
//用戶名匹配
export function nameRule (rule, value, callback) {
? ? let reg = /(^[a-zA-Z0-9]{4,10}$)/;
? ? if (value === "") {
? ? ? ? callback(new Error("請(qǐng)輸入用戶名"));
? ? } else if (!reg.test(value)) {
? ? ? ? callback(new Error("請(qǐng)輸入4-10用戶名"));
? ? } else {
? ? ? ? callback();
? ? }
}//密碼匹配
export function passRule (rule, value, callback) {
? ? let pass = /^\S*(?=\S{6,12})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/;
? ? if (value === "") {
? ? ? ? callback(new Error("請(qǐng)輸入密碼"));
? ? } else if (!pass.test(value)) {
? ? ? ? callback(new Error("請(qǐng)輸入6-12位密碼需要包含大小寫(xiě)和數(shù)字及特殊字符"));
? ? } else {
? ? ? ? callback();
? ? }
}
plugins/element.js
import Vue from 'vue'
import { Button, Tag } from 'element-ui'Vue.use(Button)
Vue.use(Tag)
3.Go后臺(tái)服務(wù)
3.2代碼結(jié)構(gòu)
3.2?源碼
controller/login.go
package controller
import (
?? ?"encoding/json"
?? ?"fmt"
?? ?"io/ioutil"
?? ?"net/http"
?? ?"path/filepath"?? ?"github.com/gin-gonic/gin"
)// post ?http://127.0.0.1:8181/login
// axios.post 和 post json處理
func LoginPost(ctx *gin.Context) {
?? ?version := ctx.DefaultQuery("version", "V1.0.0.1")?? ?//前端使用axios直接傳遞form時(shí),axios會(huì)默認(rèn)使用json,必須使用下面方式獲取json數(shù)據(jù),解析后再使用
?? ?data, _ := ioutil.ReadAll(ctx.Request.Body)
?? ?type UserInfo struct {
?? ??? ?Username string
?? ??? ?Password string
?? ?}
?? ?var u UserInfo
?? ?err := json.Unmarshal(data, &u)
?? ?if err != nil {
?? ??? ?fmt.Println(err)
?? ?}
?? ?username := u.Username
?? ?password := u.Password?? ?fmt.Println("login info:: ", version, username, password)
?? ?/*
?? ??? ?ctx.Header("Access-Control-Allow-Origin", "*")?? ??? ??? ?ctx.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
?? ??? ??? ?ctx.Header("Access-Control-Allow-Credentials", "true")
?? ??? ??? ?ctx.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
?? ??? ??? ?ctx.Header("content-type", "application/json;charset=UTF-8")?? ??? ??? ?ctx.Writer.Header().Set("Access-Control-Max-Age", "86400")
?? ??? ??? ?ctx.Writer.Header().Set("Access-Control-Allow-Methods", "*")
?? ??? ??? ?ctx.Writer.Header().Set("Access-Control-Allow-Headers", "*")
?? ??? ??? ?ctx.Writer.Header().Set("Access-Control-Expose-Headers", "*")
?? ??? ??? ?ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
?? ?*/?? ?if username == "123456" && password == "1234abcdE@" {
?? ??? ?ctx.String(http.StatusOK, "登錄成功")
?? ?} else {
?? ??? ?ctx.String(http.StatusNotFound, "用戶名或密碼錯(cuò)誤")
?? ?}
}// http://127.0.0.1:8181/formlogin
// form表單提交處理 application/x-www-form-urlencoded
func FormLoginPost(ctx *gin.Context) {?? ?//第一種
?? ?username := ctx.PostForm("username")
?? ?password := ctx.PostForm("password")?? ?//第二種
?? ?/*
?? ??? ?username := ctx.DefaultPostForm("username", "somebody")
?? ??? ?password := ctx.DefaultPostForm("password", "***")
?? ?*/?? ?//第三種
?? ?/*
?? ??? ?username, ok := ctx.GetPostForm("username")
?? ??? ?if !ok {
?? ??? ??? ?username = "取不到的話"
?? ??? ?}
?? ??? ?password, ok := ctx.GetPostForm("password")
?? ??? ?if !ok {
?? ??? ??? ?password = "***"
?? ??? ?}
?? ?*/?? ?fmt.Println("FormLoginPost :: ", username, password)
?? ?/*
?? ??? ?ctx.HTML(http.StatusOK, "home.html", gin.H{
?? ??? ??? ?"Name": ? ? username,
?? ??? ??? ?"Password": password,
?? ??? ?})
?? ?*/
?? ?ctx.JSON(http.StatusOK, gin.H{
?? ??? ?"Name": ? ? username,
?? ??? ?"Password": password,
?? ?})?? ?if username == "123456" && password == "1234abcdE@" {
?? ??? ?ctx.String(http.StatusOK, "登錄成功")
?? ?} else {
?? ??? ?ctx.String(http.StatusNotFound, "用戶名或密碼錯(cuò)誤")
?? ?}
}// form表單提交文件上傳處理 multipart/form-data
func UploadFile(ctx *gin.Context) {
?? ?file, _ := ctx.FormFile("uploadfile")
?? ?fmt.Println(file.Filename)
?? ?file_path := "upload/" + filepath.Base(file.Filename)
?? ?fmt.Println(file_path)
?? ?ctx.SaveUploadedFile(file, file_path)
?? ?ctx.String(http.StatusOK, "上傳成功")
}
server.go
package main
import (
?? ?"main/controller"
?? ?"net/http"?? ?"github.com/gin-contrib/cors"
?? ?"github.com/gin-gonic/gin"
)/*
// 錯(cuò)誤: server.go:4:2: package main/controller is not in GOROOT (/home/tiger/go/go/src/main/controller)
go mod init main//錯(cuò)誤: server.go:7:2: no required module provides package github.com/gin-gonic/gin; to add it:
go get github.com/gin-gonic/gin//處理跨域框架
go get github.com/gin-contrib/cors
*//*
當(dāng)客戶端(尤其是基于 Web 的客戶端)想要訪問(wèn) API 時(shí),服務(wù)器會(huì)決定允許哪些客戶端發(fā)送請(qǐng)求。這是通過(guò)使用稱為 CORS 來(lái)完成的,它代表跨源資源共享。
跨域資源共享 (CORS) 是一種機(jī)制,允許從提供第一個(gè)資源的域之外的另一個(gè)域請(qǐng)求網(wǎng)頁(yè)上的受限資源。
*/func CrosHandler() gin.HandlerFunc {
?? ?return func(context *gin.Context) {
?? ??? ?context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
?? ??? ?context.Header("Access-Control-Allow-Origin", "*") // 設(shè)置允許訪問(wèn)所有域
?? ??? ?context.Header("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE,UPDATE")
?? ??? ?context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma,token,openid,opentoken")
?? ??? ?context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
?? ??? ?context.Header("Access-Control-Max-Age", "172800")
?? ??? ?context.Header("Access-Control-Allow-Credentials", "true")
?? ??? ?context.Set("content-type", "application/json") //設(shè)置返回格式是json
?? ??? ?//處理請(qǐng)求
?? ??? ?context.Next()
?? ?}
}// http://127.0.0.1:8181/ping
// http://127.0.0.1:8181/index
func main() {
?? ?r := gin.Default()?? ?// 設(shè)置全局跨域訪問(wèn)
?? ?//r.Use(CrosHandler())?? ?//cors處理跨域
?? ?r.Use(cors.Default())?? ?// 返回一個(gè)json數(shù)據(jù)
?? ?r.GET("/ping", func(c *gin.Context) {
?? ??? ?c.JSON(200, gin.H{
?? ??? ??? ?"message": "pong",
?? ??? ??? ?"num": ? ? 888,
?? ??? ?})
?? ?})?? ?// 返回一個(gè)html頁(yè)面
?? ?r.LoadHTMLGlob("templates/*")
?? ?r.GET("/index", func(c *gin.Context) {
?? ??? ?c.HTML(http.StatusOK, "index.html", nil)
?? ?})?? ?r.POST("/login", controller.LoginPost)
?? ?r.POST("/formlogin", controller.FormLoginPost)
?? ?r.POST("/upload", controller.UploadFile)?? ?//r.Run() ?// <===> r.Run(":8080") ?監(jiān)聽(tīng)并在 0.0.0.0:8080 上啟動(dòng)服務(wù)
?? ?r.Run(":8181")
}
templates/home.html
歡迎進(jìn)入首頁(yè)
templates/index.html
<!DOCTYPE html>
<html lang="en">
?? ?<head>
?? ??? ?<meta charset="UTF-8"/>
?? ??? ?<title>歡迎進(jìn)入首頁(yè)</title>
?? ?</head>
?? ?<body>
?? ??? ?<h3>登錄測(cè)試</h3>
?? ??? ?<hr/>?? ??? ?<form action="http://localhost:8282/formlogin" method="post">
?? ??? ??? ?<table border=0 title="測(cè)試">
?? ??? ??? ??? ?<tr>
?? ??? ??? ??? ??? ?<td>用戶名:</td>
?? ??? ??? ??? ??? ?<td><input type="text" name="username"></td>
?? ??? ??? ??? ?</tr>
?? ??? ??? ??? ?<tr>
?? ??? ??? ??? ??? ?<td>密碼:</td>
?? ??? ??? ??? ??? ?<td><input type="password" name="password"></td>
?? ??? ??? ??? ?</tr>
?? ??? ??? ??? ?<tr>
?? ??? ??? ??? ??? ?<td colspan=2>
?? ??? ??? ??? ??? ??? ?<input type="reset" />
?? ??? ??? ??? ??? ??? ?<input type="submit" value="登錄" />
?? ??? ??? ??? ??? ?</td>
?? ??? ??? ??? ?</tr>
?? ??? ??? ?</table>
?? ??? ?</form>
?? ??? ?<br>
?? ??? ?<h3>文件上傳測(cè)試</h3>
?? ??? ?<hr/>
?? ??? ?<form action="http://localhost:8282/upload" method="post" enctype="multipart/form-data">
?? ??? ??? ?<input type="file" name="uploadfile"/>
?? ??? ??? ?<input type="submit" value="upload">
?? ??? ?</form>
?? ?</body>
</html>
3.3單測(cè)效果
http://127.0.0.1:8181/ping
http://127.0.0.1:8181/index
?
上傳文件:
8282端口nginx代理測(cè)試:
4.nginx
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
?events {
worker_connections 1024;
}
#location [ = | ~ | ~* | ^~ ] uri { }
# ~區(qū)分大小寫(xiě)的正則匹配;
# ~*不區(qū)分大小寫(xiě)的正則匹配;
# ^~常規(guī)字符串匹配;
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
fastcgi_intercept_errors on;
#gzip on;
limit_conn_zone $binary_remote_addr zone=addr:10m;
#代理靜態(tài)頁(yè)面
server {
listen 80;
server_name www.liudehua.com;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /home/tiger/nginx-1.22.1/nginx/html/dist;
index index.html;
try_files $uri $uri/ /index.html;
}
#404配置
#error_page 404 /404.html;
#location /404.html {
# alias /home/tiger/nginx-1.22.1/nginx/html/dist;
# index index.html index.htm;
#}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
#代理真正的后臺(tái)服務(wù)
server {
listen 8282;
location / {
proxy_pass http://127.0.0.1:8181/;
}
}
?# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
?# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
部署前端程序:
?啟動(dòng)nginx:
5.運(yùn)行效果
http://www.liudehua.com/
?可以看到nginx反向代理:
?
?postman測(cè)試:
不代理測(cè)試:8181端口
?代理測(cè)試:8282端口
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-608846.html
6.問(wèn)題總結(jié)
6.1 跨域訪問(wèn)錯(cuò)誤:前后臺(tái)一塊解決
6.2 form表單請(qǐng)求,axios.post請(qǐng)求Go解析處理
6.2 vue中的正則表達(dá)式
vscode安裝插件any-rule插件
ctrl + shift + p 輸入密碼,選擇正則表達(dá)式文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-608846.html
到了這里,關(guān)于Vue系列第五篇:Vue2(Element UI) + Go(gin框架) + nginx開(kāi)發(fā)登錄頁(yè)面及其校驗(yàn)登錄功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!