????運(yùn)行panic異常一旦被引發(fā)就會(huì)導(dǎo)致程序崩潰,這當(dāng)然不是我們?cè)敢饪吹降?,go語(yǔ)言提供樂(lè)專(zhuān)用于“攔截”運(yùn)行時(shí)panic的內(nèi)建函數(shù)-recover,它可以是當(dāng)前的程序從運(yùn)行時(shí)panic的狀態(tài)中恢復(fù)并重新獲得流程控制權(quán)。
為勉縣等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及勉縣網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站制作、網(wǎng)站設(shè)計(jì)、外貿(mào)網(wǎng)站建設(shè)、勉縣網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專(zhuān)業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
????注意:recover只有在defer調(diào)用的函數(shù)中有效
????如果調(diào)用了內(nèi)置函數(shù)recover,并且定義該defer語(yǔ)句的函數(shù)發(fā)生了panic異常,recover會(huì)使用程序從panic中恢復(fù),并且返回panic value,導(dǎo)致panic異常的函數(shù)不會(huì)繼續(xù)執(zhí)行,但能正常返回。在未發(fā)生panic時(shí)調(diào)用recover,recover會(huì)返回nil。
在Go語(yǔ)言的代碼中,您需要引入官方的SDK庫(kù) aliyun/serverless/fc-runtime-go-sdk/fc,并實(shí)現(xiàn)handler函數(shù)和main函數(shù)。 示例如下:
傳入的event參數(shù)是一個(gè)包含key屬性的JSON字符串,示例如下。
具體的示例解析如下:
有效的Event Handler簽名如下:
其中,InputType和OutputType與encoding/json標(biāo)準(zhǔn)庫(kù)兼容。
Event Handler的使用需遵循以下規(guī)則:
事件函數(shù)的Handler示例代碼:
最近打算為我的網(wǎng)站添加一個(gè)服務(wù)器資源監(jiān)視功能,需要服務(wù)端主動(dòng)向前端推動(dòng)資源占用數(shù)據(jù)。這時(shí)Http則不能達(dá)到要求。所以自然想到采用websocket。以前使用SpringBoot時(shí)使用websocket很簡(jiǎn)單,只需要將ServerEndpointExporter注入到bean容器并配合相應(yīng)注解即可創(chuàng)建一個(gè)websocket服務(wù)。這里要感謝各位前輩的封裝讓我們能盡快實(shí)現(xiàn)相應(yīng)的功能,但本次出于學(xué)習(xí)目并不是公司項(xiàng)目(效率穩(wěn)定性至上)同時(shí)使用的開(kāi)發(fā)語(yǔ)言為Golang,其web開(kāi)發(fā)生態(tài)也不會(huì)像Java那樣豐富,最后選擇了開(kāi)源實(shí)現(xiàn) gorilla/websocket 項(xiàng)目地址
執(zhí)行 go get github.com/gorilla/websocket 添加依賴(lài)
我們知道websocket由http升級(jí)而來(lái),首先會(huì)發(fā)送附帶Upgrade請(qǐng)求頭的Http請(qǐng)求,所以我們需要在處理Http請(qǐng)求時(shí)攔截請(qǐng)求并判斷其是否為websocket升級(jí)請(qǐng)求,如果是則調(diào)用 gorilla/websocket 庫(kù)相應(yīng)函數(shù)處理升級(jí)請(qǐng)求。
首相要?jiǎng)?chuàng)建Upgrader實(shí)例,該實(shí)例用于升級(jí)請(qǐng)求
其中 CheckOringin 是一個(gè)函數(shù),該函數(shù)用于攔截或放行跨域請(qǐng)求。函數(shù)返回值為 bool 類(lèi)型,即 true 放行, false 攔截。如果請(qǐng)求不是跨域請(qǐng)求可以不賦值,我這里是跨域請(qǐng)求并且為了方便直接返回 true
此時(shí)已經(jīng)成功升級(jí)為websocket連接并獲得一個(gè)conn實(shí)例,之后的發(fā)送接收操作皆有conn完成其類(lèi)型為websocket.Conn。
首先向客戶端發(fā)送消息使用 WriteMessage(messageType int, data []byte) ,參數(shù)1為消息類(lèi)型,參數(shù)2消息內(nèi)容
示例:
接受客戶端消息使用 ReadMessage() 該操作會(huì)阻塞線程所以建議運(yùn)行在其他協(xié)程上。該函數(shù)有三個(gè)返回值分別是,接收消息類(lèi)型、接收消息內(nèi)容、發(fā)生的錯(cuò)誤當(dāng)然正常執(zhí)行時(shí)錯(cuò)誤為 nil。一旦連接關(guān)閉返回值類(lèi)型為-1可用來(lái)終止讀操作。
示例:
同時(shí)可以為連接設(shè)置關(guān)閉連接監(jiān)聽(tīng),函數(shù)為 SetCloseHandler(h func(code int, text string) error) 函數(shù)接收一個(gè)函數(shù)為參數(shù),參數(shù)為nil時(shí)有一個(gè)默認(rèn)實(shí)現(xiàn),其源碼為:
可以看到作為參數(shù)的函數(shù)的參數(shù)為int和string類(lèi)型正好和前端的close(long string)對(duì)應(yīng)即前端調(diào)用close(long string)關(guān)閉連接后兩個(gè)參數(shù)會(huì)被發(fā)送給后端并最終被 func(code int, text string) error 所使用。
示例:
則斷開(kāi)連接時(shí)將打印code和text
注意:要想使斷連處理生效必須要有 ReadMessage() 操作否則不會(huì)觸發(fā)斷連處理操作。
以上是常用基礎(chǔ)操作點(diǎn)擊 官方API手冊(cè) 學(xué)習(xí)更多。
最后:大幻夢(mèng)森羅萬(wàn)象狂氣斷罪眼\ (??) /
token過(guò)期自動(dòng)跳轉(zhuǎn)到登錄頁(yè)面
設(shè)置token有效期為2小時(shí),超過(guò)兩小時(shí) token失效 ,接口返回結(jié)果:{code:0,msg:'token過(guò)期',}
每次路由跳轉(zhuǎn)都會(huì)對(duì)token進(jìn)行判斷,設(shè)置一個(gè)全局的beforeEach鉤子函數(shù),如果token存在就跳到你所需要的頁(yè)面,否則直接跳轉(zhuǎn)到登錄頁(yè)面,讓用戶重新存取token
全局路由鉤子:router.beforeEach
router.beforeEach(async (to, from, next) = {
? ? ? ? //獲取token
? ? ? ? const hasToken = getToken()
? ? ? ? if (hasToken) {
? ? ? ? ? ? //token存在,如果當(dāng)前跳轉(zhuǎn)的路由是登錄界面
? ? ? ? ? ? if (to.path === '/login') {
? ? ? ? ? ? ? ? // if is logged in, redirect to the home page
? ? ? ? ? ? ? ? next({
? ? ? ? ? ? ? ? ? ? path: '/'
? ? ? ? ? ? ? ? })
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? //在這里,就拉去用戶權(quán)限,判斷用戶是否有權(quán)限訪問(wèn)這個(gè)路由
? ? ? ? ? ? } catch (error) {
? ? ? ? ? ? ? ? // remove token and go to login page to re-login
? ? ? ? ? ? ? ? await store.dispatch('user/resetToken')
? ? ? ? ? ? ? ? Message.error(error || 'Has Error')
? ? ? ? ? ? ? ? next(`/login?redirect=${to.path}`)
? ? ? ? ? ? }
? ? ? ? } else {
? ? ? ? ? ? //token不存在
? ? ? ? ? ? if (whiteList.indexOf(to.path) !== -1) {
? ? ? ? ? ? ? ? //如果要跳轉(zhuǎn)的路由在白名單里,則跳轉(zhuǎn)過(guò)去
? ? ? ? ? ? ? ? next()
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? //否則跳轉(zhuǎn)到登錄頁(yè)面
? ? ? ? ? ? ? ? next(`/login?redirect=${to.path}`)
? ? ? ? ? ? }
? ? ? ? }
? ? })
請(qǐng)求攔截 設(shè)置
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 5000
})
//發(fā)送請(qǐng)求時(shí)把token攜帶過(guò)去
service.interceptors.request.use(
config = {
if (store.getters.token) {
? config.headers['sg-token'] = getToken()
}
return config
},
error = {
console.log(error)
return Promise.reject(error)
}
)
//請(qǐng)求響應(yīng)
service.interceptors.response.use(
response = {
console.log(response.data)
const res = response.data
// token過(guò)期,重返登錄界面
if (res.code === 0) {
? store.dispatch('user/logout').then(() = {
? ? location.reload(true)
? })
}
return res
},
error = {
Message({
? message: error.msg,
? type: 'error',
? duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service