JavaScript 中使用fetch的AbortController和取消功能:如何在Go 實現

更新 發佈閱讀 13 分鐘
vocus|新世代的創作平台


有多種情況下我們需要從API取消請求:

  1. 如果我們正在建立一個支付系統,並且請求一直進行,但使用者希望立即取消這筆訂單。這就是為什麼開發者會建立這個功能的原因。
  2. 從電子商務購買商品。使用者意外關閉了頁面,無法立即返回上一頁。
  3. 訂閱取消。

......等等

這將對對這個系統沒有信心的使用者產生影響。因此,開發者需要認真對待這個問題。


我使用Vue和Go建立了一個簡單的前端系統和後端系統的示範。


後端部分

mkdir cancellation-demo && cd cancellation-demo

建立資料夾,稱為 `cancellation-demo`

go mod init callcellation-demo && \ 
touch main.go && \
go get github.com/gin-gonic/gin

從go module和main.go開始。導入gin套件。

以下是main.go的內容。建立一個簡單的Hello World。

package main

import (
"net/http"
"github.com/gin-gonic/gin"
)

func CancelHandler(ctx *gin.Context) {
ctx.String(http.StatusOK, "hello world")
}

func main() {
router := gin.Default()
router.GET("/", EchoHandler)
router.Run()
}

我們的目標是在收到請求後等待3秒,然後發送一個文字回應"Hello World"。如果使用者在3秒內取消了請求,我們將停止處理並打印結果,告知系統管理員該請求已被取消

以下範例

func CancelHandler(ctx *gin.Context) {
ctx.String(http.StatusOK, "hello world")
}

我們改寫成

func CancelHandler(ctx *gin.Context) {
responseResult := make(chan string)

go func() {
time.Sleep(3 * time.Second)
responseResult <- "hello world"
}()

for {
select {
case result := <-responseResult:
ctx.String(http.StatusOK, result)
return
case <-ctx.Request.Context().Done():
log.Println("abort triggerred.Cancellation happen")
ctx.AbortWithStatus(http.StatusNoContent)
return
}
}
}

讓我來解釋這部分:

我們需要建立一個goroutine和channel來傳送資料,並使用CancelHandler接收channel和ctx.Context().Done()來傳送chan類型。

這有助於我們檢查是否在請求被取消時收到中止訊號。這個方法將由中止訊號觸發。

因為我們需要建立一個在不同端口上監聽的前端專案,這導致了跨來源資源共享(CORS)的問題。因此,我們需要建立一個中間件(Middleware)來解決這個問題。

func CorsMiddleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
ctx.Writer.Header().Set("Access-Control-allow-Credentials", "true")
ctx.Writer.Header().Set("Access-Control-allow-Method", "GET, POST, OPTIONS, PUT, PATCH, DELETE")
ctx.Writer.Header().Set("Access-Control-allow-Headers", "Authorization, Accept,Accept-Encoding, Content-Type,Content-Length, Cache-Control, Origin, X-CSRF-Token, X-Requested-With")
if ctx.Request.Method == http.MethodOptions {
ctx.AbortWithStatus(http.StatusNoContent)
 return
}
ctx.Next()
}
}

最後,我們的後端專案的部分就會看起來像這樣

package main

import (
"log"
"net/http"
"time"

"github.com/gin-gonic/gin"
)

func CorsMiddleware() gin.HandlerFunc {
return func(ctx *gin.Context) {
ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*")
ctx.Writer.Header().Set("Access-Control-allow-Credentials", "true")
ctx.Writer.Header().Set("Access-Control-allow-Method", "GET, POST, OPTIONS, PUT, PATCH, DELETE")
ctx.Writer.Header().Set("Access-Control-allow-Headers", "Authorization, Accept,Accept-Encoding, Content-Type,Content-Length, Cache-Control, Origin, X-CSRF-Token, X-Requested-With")
if ctx.Request.Method == http.MethodOptions {
ctx.AbortWithStatus(http.StatusNoContent)
return
}
ctx.Next()
}
}

func CancelHandler(ctx *gin.Context) {
responseResult := make(chan string)

go func() {
time.Sleep(3 * time.Second)
responseResult <- "hello world"
}()

for {
select {
case result := <-responseResult:
ctx.String(http.StatusOK, result)
return
case <-ctx.Request.Context().Done():
log.Println("abort triggered")
ctx.AbortWithStatus(http.StatusNoContent)
return
}
}

}

func main() {
router := gin.Default()
router.Use(CorsMiddleware())
router.GET("/", CancelHandler)
router.Run()
}

現在換前端的部分

我們前端使用 vue 作為我們的前端框架

pnpm create vite --template vue-ts web && \
cd web && \
pnpm install

注意:對了,我本人個人是喜歡用 pnpm 作為我的 package manager,
不代表不能用 npm

然後我們將建立一個簡單的使用AbortController的fetch範例。這部分是向http://localhost:8080發送請求的部分。切記我們的後端專案在端口8080上監聽。

import { ref } from 'vue';
const abortReference = ref(new AbortController());

const getRequest = async () => {
  abortReference.value = new AbortController();
  try {
   const response = await fetch('http://localhost:8080', {
       method: 'GET',
      signal: abortReference.value.signal,
  })
   const mainContent = await response.text();
    console.log(mainContent);
  } catch{
   console.error('api error');
  }
}

取消功能的部分

const quitRequest = () => {
console.log('cancel request');
abortReference.value.abort();
}

現在我們把兩個方法取代原本專案的 app.vue

<script setup lang="ts">
import { ref } from 'vue';
const abortReference = ref(new AbortController());

const getRequest = async () => {
abortReference.value = new AbortController();
  try {
  const response = await fetch('http://localhost:8080', {
    method: 'GET',
     signal: abortReference.value.signal,
})
  const mainContent = await response.text();
  console.log(mainContent);
} catch{
  console.error('api error');
}
}

const quitRequest = () => {
console.log('cancel request');
abortReference.value.abort();
}

</script>

<template>
<button @click="getRequest">
click to request
</button>
<button @click="quitRequest">
Abort Request
</button>
</template>

這樣就大功告成了,

pnpm dev

然後打開瀏覽器我們會看到的結果

vocus|新世代的創作平台

如果有任何問題歡迎跟我討論,感謝你得閱讀

以下是我的 medium 帳號

還有我發表的英文版原文 ,如果對我的創作有興趣歡迎追蹤捧場

留言
avatar-img
Michael 的程式平台
3會員
5內容數
如果對網頁開發,區塊鏈開發,手機應用開發,桌面應用開發有興趣的可以來看看
2024/06/29
前言 從零開始構建一個 DateTimePicker 可能看起來令人畏懼,但試想一下你將獲得的靈活性和控制力。在這個系列中,我們將逐步揭開構建過程的神秘面紗,讓您能夠創建一個完全符合需求的自定義 DateTimePicker。 本文章,屬於付費系列的文章,這篇文章,我會希望讀者可以得到的
Thumbnail
2024/06/29
前言 從零開始構建一個 DateTimePicker 可能看起來令人畏懼,但試想一下你將獲得的靈活性和控制力。在這個系列中,我們將逐步揭開構建過程的神秘面紗,讓您能夠創建一個完全符合需求的自定義 DateTimePicker。 本文章,屬於付費系列的文章,這篇文章,我會希望讀者可以得到的
Thumbnail
2024/06/15
# 簡介 身為一位專注於 Vue.js 的前端開發者,這是我第一次嘗試構建 Flutter 網頁應用。讓我們開始吧! ## 第一次嘗試 ### 第一步:創建一個 Flutter 應用 首先,通過運行以下命令來創建一個新的 Flutter 項目: ```sh flutter
Thumbnail
2024/06/15
# 簡介 身為一位專注於 Vue.js 的前端開發者,這是我第一次嘗試構建 Flutter 網頁應用。讓我們開始吧! ## 第一次嘗試 ### 第一步:創建一個 Flutter 應用 首先,通過運行以下命令來創建一個新的 Flutter 項目: ```sh flutter
Thumbnail
2024/01/14
我看完影片只有一個想法,台灣目前還是用傳統方式開票還有利用人力的方式進行, 我認為這樣並不是很對,因為會增加人為疏失的可能性以外,還有可能造成做票或是小動作的嫌疑,我認為即便有人監票,那種很會『變魔術』的人,也會讓監票員造成困難 我身為一名軟體工程師,是要想 solution 的,
Thumbnail
2024/01/14
我看完影片只有一個想法,台灣目前還是用傳統方式開票還有利用人力的方式進行, 我認為這樣並不是很對,因為會增加人為疏失的可能性以外,還有可能造成做票或是小動作的嫌疑,我認為即便有人監票,那種很會『變魔術』的人,也會讓監票員造成困難 我身為一名軟體工程師,是要想 solution 的,
Thumbnail
看更多
你可能也想看
Thumbnail
本文深度解析賽勒布倫尼科夫的舞臺作品《傳奇:帕拉贊諾夫的十段殘篇》,如何以十段殘篇,結合帕拉贊諾夫的電影美學、象徵意象與當代政治流亡抗爭,探討藝術在儀式消失的現代社會如何承接意義,並展現不羈的自由靈魂。
Thumbnail
本文深度解析賽勒布倫尼科夫的舞臺作品《傳奇:帕拉贊諾夫的十段殘篇》,如何以十段殘篇,結合帕拉贊諾夫的電影美學、象徵意象與當代政治流亡抗爭,探討藝術在儀式消失的現代社會如何承接意義,並展現不羈的自由靈魂。
Thumbnail
RESTful Web 服務是現代 Web 和移動應用的核心,它們提供了一個標準化的方式來互動和交換數據。使用Gin構建這些服務是一種流行選擇,還記得之前提過的 嗎?本文將介紹一些最佳實踐,幫助你創建高效和可維護的RESTful服務。
Thumbnail
RESTful Web 服務是現代 Web 和移動應用的核心,它們提供了一個標準化的方式來互動和交換數據。使用Gin構建這些服務是一種流行選擇,還記得之前提過的 嗎?本文將介紹一些最佳實踐,幫助你創建高效和可維護的RESTful服務。
Thumbnail
Gin框架深入解析:路由和處理器 Hey 朋友們!上回我們介紹了 Gin 框架的基礎知識,今天我們要更深入一些,看看 Gin 如何處理路由和相對應的處理器吧! Gin 的路由機制非常靈活和高效,可以快速地配置不同的路由方式。再配合上處理器函數,讓我們可以有針對性地處理不同路由的請求。探索完今
Thumbnail
Gin框架深入解析:路由和處理器 Hey 朋友們!上回我們介紹了 Gin 框架的基礎知識,今天我們要更深入一些,看看 Gin 如何處理路由和相對應的處理器吧! Gin 的路由機制非常靈活和高效,可以快速地配置不同的路由方式。再配合上處理器函數,讓我們可以有針對性地處理不同路由的請求。探索完今
Thumbnail
長期以來,西方美學以《維特魯威人》式的幾何比例定義「完美身體」,這種視覺標準無形中成為殖民擴張與種族分類的暴力工具。本文透過分析奈及利亞編舞家庫德斯.奧尼奎庫的舞作《轉轉生》,探討當代非洲舞蹈如何跳脫「標本式」的文化觀看。
Thumbnail
長期以來,西方美學以《維特魯威人》式的幾何比例定義「完美身體」,這種視覺標準無形中成為殖民擴張與種族分類的暴力工具。本文透過分析奈及利亞編舞家庫德斯.奧尼奎庫的舞作《轉轉生》,探討當代非洲舞蹈如何跳脫「標本式」的文化觀看。
Thumbnail
全新版本的《三便士歌劇》如何不落入「復刻經典」的巢臼,反而利用華麗的秀場視覺,引導觀眾在晚期資本主義的消費愉悅之中,而能驚覺「批判」本身亦可能被收編——而當絞繩升起,這場關於如何生存的黑色遊戲,又將帶領新時代的我們走向何種後現代的自我解構?
Thumbnail
全新版本的《三便士歌劇》如何不落入「復刻經典」的巢臼,反而利用華麗的秀場視覺,引導觀眾在晚期資本主義的消費愉悅之中,而能驚覺「批判」本身亦可能被收編——而當絞繩升起,這場關於如何生存的黑色遊戲,又將帶領新時代的我們走向何種後現代的自我解構?
Thumbnail
嗨,各位開發者!現代 Web 開發越來越傾向於前後端分離,使得前端框架和後端框架的協同工作變得非常重要。在這篇文章中,我們將專注於兩個極受歡迎的框架 —— Gin 和 Vue.js,探討如何將它們整合起來,為你的用戶提供流暢的Web 體驗。
Thumbnail
嗨,各位開發者!現代 Web 開發越來越傾向於前後端分離,使得前端框架和後端框架的協同工作變得非常重要。在這篇文章中,我們將專注於兩個極受歡迎的框架 —— Gin 和 Vue.js,探討如何將它們整合起來,為你的用戶提供流暢的Web 體驗。
Thumbnail
微前端是一種現代前端架構,旨在將大型前端應用拆分為獨立、可獨立部署的小模組。這與微服務在後端的策略相似。 本文將探討微前端的基本概念,以及如何在基於Gin的後端系統中實施它,從而實現真正的全棧模組化。
Thumbnail
微前端是一種現代前端架構,旨在將大型前端應用拆分為獨立、可獨立部署的小模組。這與微服務在後端的策略相似。 本文將探討微前端的基本概念,以及如何在基於Gin的後端系統中實施它,從而實現真正的全棧模組化。
Thumbnail
嗨,開發者們!在網頁應用的世界中,即時通訊是一個越來越重要的特點。WebSocket提供了一個高效的方式來支持這種通訊,並且能夠在客戶端和伺服器之間提供雙向的即時通訊。本篇文章將會帶你走進WebSocket的世界,並學習如何在Gin框架中實現它。
Thumbnail
嗨,開發者們!在網頁應用的世界中,即時通訊是一個越來越重要的特點。WebSocket提供了一個高效的方式來支持這種通訊,並且能夠在客戶端和伺服器之間提供雙向的即時通訊。本篇文章將會帶你走進WebSocket的世界,並學習如何在Gin框架中實現它。
Thumbnail
若說易卜生的《玩偶之家》為 19 世紀的女性,開啟了一扇離家的窄門,那麼《海妲.蓋柏樂》展現的便是門後的窒息世界。本篇文章由劇場演員 Amily 執筆,同為熟稔文本的演員,亦是深刻體察制度縫隙的當代女性,此文所看見的不僅僅是崩壞前夕的最後發聲,更是女人被迫置於冷酷的制度之下,步步陷入無以言說的困境。
Thumbnail
若說易卜生的《玩偶之家》為 19 世紀的女性,開啟了一扇離家的窄門,那麼《海妲.蓋柏樂》展現的便是門後的窒息世界。本篇文章由劇場演員 Amily 執筆,同為熟稔文本的演員,亦是深刻體察制度縫隙的當代女性,此文所看見的不僅僅是崩壞前夕的最後發聲,更是女人被迫置於冷酷的制度之下,步步陷入無以言說的困境。
Thumbnail
微服務架構是一種把應用程序劃分成一系列小的、獨立的服務,每個服務都運行在其自己的進程中,並與其他服務通過 API 或 RPC 通信。在這篇文章中,我們將使用 Gin 作為我們的 HTTP 框架,並使用 gRPC 來實現服務間的通信。
Thumbnail
微服務架構是一種把應用程序劃分成一系列小的、獨立的服務,每個服務都運行在其自己的進程中,並與其他服務通過 API 或 RPC 通信。在這篇文章中,我們將使用 Gin 作為我們的 HTTP 框架,並使用 gRPC 來實現服務間的通信。
Thumbnail
嗨各位!歡迎來到這個系列,今天我們要探索的是 Gin 框架!如果你對於開發高效且輕量級的 Web 應用感興趣,那你絕對不能錯過這篇!
Thumbnail
嗨各位!歡迎來到這個系列,今天我們要探索的是 Gin 框架!如果你對於開發高效且輕量級的 Web 應用感興趣,那你絕對不能錯過這篇!
Thumbnail
大家好!隨著微服務和前後端分離的架構日益普及,RESTful API 已經成為 Web 開發的核心。透過 Gin,我們可以輕鬆地設計和實現高效能的 API。今天,我們就來探討如何在 Gin 中設計優雅且實用的RESTful API
Thumbnail
大家好!隨著微服務和前後端分離的架構日益普及,RESTful API 已經成為 Web 開發的核心。透過 Gin,我們可以輕鬆地設計和實現高效能的 API。今天,我們就來探討如何在 Gin 中設計優雅且實用的RESTful API
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News