【趣味連載】攻城獅上傳視頻與普通人上傳視頻:(一)生成結構化數據

来源:http://www.cnblogs.com/ios122/archive/2017/12/07/7996524.html
-Advertisement-
Play Games

當知道要上傳的視頻資料從20條變成100條時,我就明白,絕對不能再人工處理了。他們總是想當然的認為,錄入一條數據需要1分鐘,那錄入20條數據就是20分鐘,錄入100條數據,不就是100分鐘嗎?我有時候,真的很想問問他們,沒有考慮過人是會犯錯的嗎?數據越多,出錯的可能就越大;但是數據本身,又是不允許出... ...


背景

當知道要上傳的視頻資料從20條變成100條時,我就明白,絕對不能再人工處理了。他們總是想當然的認為,錄入一條數據需要1分鐘,那錄入20條數據就是20分鐘,錄入100條數據,不就是100分鐘嗎?我有時候,真的很想問問他們,沒有考慮過人是會犯錯的嗎?數據越多,出錯的可能就越大;但是數據本身,又是不允許出現紕漏的。那拿什麼去保證數據的正確性?刷臉?可能嗎?

大多數時候,類似的爭論,最終幾乎總是會以他們的一句“我不懂技術,你們看著辦吧”結束。所以,也懶得去做口舌之爭。我儘力儘快做;但是你承不承認事情本身的複雜度,並不會影響事情本身的複雜度。

回到問題本身,究竟如何處理新到來的100條數據以及以後更多的數據,確實是一個必須想辦法徹底解決下的問題。

我拿到的原始數據

此處適當象徵性的描述下我拿到的數據。以下討論,單以 10 條數據為例。

一個 word 文檔,是一組問題。

內容假定是:

1.【smart-transform】取自 Atom 的 babeljs&coffeescript&typescript 智能轉 es5 庫
2.【YFMemoryLeakDetector】人人都能理解的 iOS 記憶體泄露檢測工具類
3.【玩轉樹莓派】使用 sinopia 搭建私有 npm 伺服器
4.【小技巧解決大問題】使用 frp 突破阿裡雲主機無彈性公網 IP 不能用作 Web 伺服器的限制
5.【樹莓派自動化應用實例】整點提醒自己休息五分鐘
6. 藉助 frp 隨時隨地訪問自己的樹莓派
7.【LuaJIT版】從零開始在 macOS 上配置 Lua 開發環境
8.【最新版】從零開始在 macOS 上配置 Lua 開發環境
9. 關於混合應用開發的未來的一些思考
10.記錄我發現的第一個關於 Google 的 Bug

是的,內容中還有各種中文標點。他們有相當一部分人不理解攻城獅為什麼喜歡用英文標點,甚至還有人以此為由說我們小學標點符號沒學好。懶得解釋那麼多,但是既然給出來了,作為純文本,也不用管這麼多,照單全收就行了。符號習慣問題本身,也是一個無傷大雅的問題。

另一個 word 文檔,是一組問題對應的 Luis 語義分析結果

微軟的 Luis 語義分析服務,勉強算是和人工智慧沾點邊吧,感興趣的請自行瞭解下。從客戶端角度來說,你給它一個文本字元串,他們分析出來和這個字元串匹配度最高的某個預錄入的答案的唯一標記。每個唯一標記 ID,被稱作一個 intent。每次請求,最多只有一個匹配度最高的 intent。

感覺已經有的 word 問題,我們的後端小伙伴,送來了另一個 word 文檔:

1. smart_transform
2. memory_leakDetector
3. sinopia_npm
4. frp_ip
5. tip_rest
6. frp_anywhere
7. luajit_macos
8. lua_macos
9. app_future
10. google_bug

又是非結構化的數據。顯而易見,我們可愛的後端同學,只是簡單完成了錄入,自己沒有做必要的單元測試。這是在等著我去發現問題啊。很久很久以前,我總是幻想著,所有的攻城獅,必然都是各種自動化測試用例,就像樹上寫的各種敏捷,各種快速迭代。事實上,我見到的許多所謂的敏捷式開發,最終其實只是把成本後置,各種技術債。出來混,真的遲早是要換的。100個問題,逐一去驗證,真的是很耗費時間的,而且最終有問題的,數量也不會太多。也就說說,如果手動去做,很有可能尋找問題的時間,要遠遠大於發現問題的時間。所以,自動化批量測試,是顯而易見的。根據不同的場景和需要,快速構建基本夠用的批量自動化測試工具鏈,應該成為每個攻城獅的必修課。

一組勉強算是有規律的分文件夾放置的視頻

我依然是象徵性的描述下,結構類似於:

/videos/樹莓派/【smart-transform】取自 Atom 的 babeljs&coffeescript&typescript 智能轉 es5 庫.mp4
/videos/樹莓派/【YFMemoryLeakDetector】人人都能理解的 iOS 記憶體泄露檢測工具類.mp4
/videos/樹莓派/【玩轉樹莓派】使用 sinopia 搭建私有 npm 伺服器.mp4
/videos/樹莓派/【小技巧解決大問題】使用 frp 突破阿裡雲主機無彈性公網 IP 不能用作 Web 伺服器的限制.mp4
/videos/frp/【樹莓派自動化應用實例】整點提醒自己休息五分鐘.mp4
/videos/frp/藉助 frp 隨時隨地訪問自己的樹莓派.mp4
/videos/Lua/【LuaJIT版】從零開始在 macOS 上配置 Lua 開發環境.mp4
/videos/Lua/【最新版】從零開始在 macOS 上配置 Lua 開發環境.mp4
/videos/Lua/關於混合應用開發的未來的一些思考.mp4
/videos/Lua/記錄我發現的第一個關於 Google 的 Bug.mp4

目標數據要求

intent 必須和問題關聯起來

顯而易見,應該使用 intent 作為數據的唯一 id。為了便於處理,索性寫成了一個 JS 模塊。之所以不直接用 JSON,是因為模塊比 JSON 文件,更靈活性,後期擴展方便,如果有的話。

這一步是必須手動做的,或者說總是需要有一個人手動去做的。為了效率,團隊內總是需要有一個人必須要充當這個角色。

大致處理下,初版結構 intent_info.js 大概類似這樣:

module.exports = {
  /* 樹莓派 */
  "smart_transform":"【smart-transform】取自 Atom 的 babeljs&coffeescript&typescript 智能轉 es5 庫",
  "memory_leakDetector":"【YFMemoryLeakDetector】人人都能理解的 iOS 記憶體泄露檢測工具類",
  "sinopia_npm":"【玩轉樹莓派】使用 sinopia 搭建私有 npm 伺服器",
  "frp_ip":"【小技巧解決大問題】使用 frp 突破阿裡雲主機無彈性公網 IP 不能用作 Web 伺服器的限制",
  /* frp */
  "tip_rest":"【樹莓派自動化應用實例】整點提醒自己休息五分鐘",
  "frp_anywhere":"藉助 frp 隨時隨地訪問自己的樹莓派",
  /* Lua */
  "luajit_macos":"【LuaJIT版】從零開始在 macOS 上配置 Lua 開發環境",
  "lua_macos":"【最新版】從零開始在 macOS 上配置 Lua 開發環境",
  "app_future":"關於混合應用開發的未來的一些思考",
  "google_bug":"記錄我發現的第一個關於 Google 的 Bug",
}

排序

排序,是需要增加一個新的欄位 order。不過,我就直接上面的類似 JSON 的結構來排序的。因為排序是由另外一個人做,懂技術,操作很簡單些。

經過對方排序後,intent_info.js,可能變成了這樣:

module.exports = {
  /* 樹莓派 */
  "smart_transform":"【smart-transform】取自 Atom 的 babeljs&coffeescript&typescript 智能轉 es5 庫",
  "memory_leakDetector":"【YFMemoryLeakDetector】人人都能理解的 iOS 記憶體泄露檢測工具類",
  "sinopia_npm":"【玩轉樹莓派】使用 sinopia 搭建私有 npm 伺服器",
  "frp_ip":"【小技巧解決大問題】使用 frp 突破阿裡雲主機無彈性公網 IP 不能用作 Web 伺服器的限制",
  /* Lua */
  "luajit_macos":"【LuaJIT版】從零開始在 macOS 上配置 Lua 開發環境",
  "lua_macos":"【最新版】從零開始在 macOS 上配置 Lua 開發環境",
  "app_future":"關於混合應用開發的未來的一些思考",
  "google_bug":"記錄我發現的第一個關於 Google 的 Bug",
  /* frp */
  "tip_rest":"【樹莓派自動化應用實例】整點提醒自己休息五分鐘",
  "frp_anywhere":"藉助 frp 隨時隨地訪問自己的樹莓派",
}

在上面的優先顯示。在真正生成 order 欄位時,是藉助 Node 一個不太可靠的特性: 字典遍歷時,會基於key的書寫順序來遍歷。這一點,在 Node 和 Android 瀏覽器上都是成立的,在 safari 上,無效。一般開發時,不應依賴於這一點,不過目前,我只是需要一個夠用的東西。Node 的這個特性,在短時間內,應該是不會有改變的。

分類

沒過幾天,果然又加了新需求,說是視頻太多了,太雜亂,想給每個視頻加個分類,然後可以按分類查看視頻。

好,那我給你加個分類:

module.exports = {
  /* 樹莓派 */
  "樹莓派":"_category",
  "smart_transform":"【smart-transform】取自 Atom 的 babeljs&coffeescript&typescript 智能轉 es5 庫",
  "memory_leakDetector":"【YFMemoryLeakDetector】人人都能理解的 iOS 記憶體泄露檢測工具類",
  "sinopia_npm":"【玩轉樹莓派】使用 sinopia 搭建私有 npm 伺服器",
  "frp_ip":"【小技巧解決大問題】使用 frp 突破阿裡雲主機無彈性公網 IP 不能用作 Web 伺服器的限制",
  /* Lua */
  "Lua":"_category",
  "luajit_macos":"【LuaJIT版】從零開始在 macOS 上配置 Lua 開發環境",
  "lua_macos":"【最新版】從零開始在 macOS 上配置 Lua 開發環境",
  "app_future":"關於混合應用開發的未來的一些思考",
  "google_bug":"記錄我發現的第一個關於 Google 的 Bug",
  /* frp */
  "frp":"_category",
  "tip_rest":"【樹莓派自動化應用實例】整點提醒自己休息五分鐘",
  "frp_anywhere":"藉助 frp 隨時隨地訪問自己的樹莓派",
}

新加了幾個值為 **_category** 的欄位。當檢測到值為 **_category** 時,就自動判定為是一個分類。我這種處理方式,免不了引來一陣唏噓。但是,許多時候,你選擇的技術策略,都必鬚根據項目所處的狀態和各種條件,去綜合權衡。我只有幾十分鐘時間去重新規劃和整理100條數據。可能真的沒法想太多。需求總是變化的,不知道明天又會變成什麼樣,可能再進一步,就變成”過度設計“了。另外,項目本身, intent 本身約定了自己特有命名規律,是可以安全認為 intent 和 分類一定不會重覆的。

問題和視頻關聯

在讀取 intent_info.js 中的足夠可信的結構化數據後,我會動態建立問題和視頻的關聯。這個過程中,可能需要適當修改問題和視頻的標題。為了避免遺漏,一個標題,如果沒有對應的視頻或對應多個視頻,就直接crash。有些霸道,但總比後期一個一個比對排查,省太多事了。結合問題和視頻標題的特點,我專門封裝了一個方法:

/* 獲取某個標題對應的本地路徑.
為了避免未知錯誤,如果找不到或找到多個,就直接 crash.

@return  本地視頻的相對路徑.
 */
function localVideoPath(title)
{
  let path = require("path")
  let fs = require ('fs-plus')
  let fse = require('fs-extra')
  let os = require("os")
  let {execSync} = require("child_process")

  let videoDir = path.resolve(__dirname,"./videos")

  let videos = fs.listTreeSync(videoDir)
                  .filter(item=>{
                    return [".mov",".mp4"].includes(path.extname(item))
                  })
                  .map(item=>{
                    return path.relative(__dirname,item)
                  })

  /* 一個標題,能且只能對應一個視頻,否則就拋出異常. */
  let localVideoPath = null

  for (let item of videos) {
    if (item.includes(title)) {
      if (localVideoPath) {
        const tip = `致命異常: ${title} 對應的視頻重覆:
        ${localVideoPath}
        ${item}`

        throw new Error(tip)
      }

      localVideoPath = item
    }
  }

  if (!localVideoPath) {
    const tip = `致命異常!這個標題竟然沒有對應的視頻:\n${title}`

    throw new Error(tip)
  }

  return localVideoPath
}

見碼如唔

完整的自動化處理成結構數據的邏輯如下,都集中在 make_data.js 中。

/* 生成帶有排序等信息的文件. */

/* 支持自動生成數據. */
makeDataWithOrder()
function makeDataWithOrder()
{
  const fs = require('fs-extra')
  const path = require('path')

  const intentInfo = require("./intent_info.js")

  let intentInfoNew = []
  let index = 1

  /* 在node中遍歷時,key的順序是和原始key的順序對應的.
  這個特性,並不總是有效,比如在 ios 瀏覽器中.
  目前,僅僅是夠用. */
  let category = ""
  for (let intent in intentInfo) {
    if (intentInfo[intent] == "_category") { /* 說明是一個分類標記. */
      category = intent
      continue
    }
    let title = intentInfo[intent]
    const local_path = localVideoPath(title)
    intentInfoNew.push({
      "type":"video",
      "content":"",
      "intent": intent,
      "title": title,
      "order": index,
      "local_video_path": local_path,
      "ext": path.extname(local_path),
      "category":category,
    })

    ++ index
  }

  localVideoLoseCheck(intentInfoNew)
  const dataPath = path.resolve(__dirname, "./data.json")
  fs.writeJsonSync(dataPath, intentInfoNew)
  console.log(`恭喜!數據已寫入 ${dataPath}`)
}

/* 確保視頻總數與intent總數是對應的,防止有視頻遺漏.
有視頻沒有對應問題時,會直接拋出異常.
 */
function localVideoLoseCheck(intents)
{
  /* 先把視頻信息處理成 key-value. */
  let path = require("path")
  let fs = require ('fs-plus')
  let fse = require('fs-extra')
  let os = require("os")
  let {execSync} = require("child_process")

  let videoDir = path.resolve(__dirname,"./videos")
  let videoDict = fs.listTreeSync(videoDir)
                  .filter(item=>{
                    return [".mov",".mp4"].includes(path.extname(item))
                  })
                  .map(item=>{
                    return path.relative(__dirname,item)
                  })
                  .reduce((sum,item,idx)=>{
                    sum[item] = false
                    return sum
                  },{})

  for (let item of intents) {
    videoDict[item.local_video_path] = true
  }

  /* 尋找缺失的. */
  let loses = []
  for (let item in videoDict) {
    if (!videoDict[item]) {
      loses.push(item)
    }
  }

  if (loses.length) {
    const tip = `一下 ${loses.length} 個視頻沒有對應的問題:
    ${JSON.stringify(loses)}`
    throw new Error(tip)
  }
}

/* 獲取某個標題對應的本地路徑.
為了避免未知錯誤,如果找不到或找到多個,就直接 crash.

@return  本地視頻的相對路徑.
 */
function localVideoPath(title)
{
  let path = require("path")
  let fs = require ('fs-plus')
  let fse = require('fs-extra')
  let os = require("os")
  let {execSync} = require("child_process")

  let videoDir = path.resolve(__dirname,"./videos")

  let videos = fs.listTreeSync(videoDir)
                  .filter(item=>{
                    return [".mov",".mp4"].includes(path.extname(item))
                  })
                  .map(item=>{
                    return path.relative(__dirname,item)
                  })

  /* 一個標題,能且只能對應一個視頻,否則就拋出異常. */
  let localVideoPath = null

  for (let item of videos) {
    if (item.includes(title)) {
      if (localVideoPath) {
        const tip = `致命異常: ${title} 對應的視頻重覆:
        ${localVideoPath}
        ${item}`

        throw new Error(tip)
      }

      localVideoPath = item
    }
  }

  if (!localVideoPath) {
    const tip = `致命異常!這個標題竟然沒有對應的視頻:\n${title}`

    throw new Error(tip)
  }

  return localVideoPath
}

我們在項目目錄執行

node ./make_data.js

就可以得到我們想要的結構化的數據:

[
  {
    "type": "video",
    "content": "",
    "intent": "smart_transform",
    "title": "【smart-transform】取自 Atom 的 babeljs:coffeescript:typescript 智能轉 es5 庫",
    "order": 1,
    "local_video_path": "videos/樹莓派/【smart-transform】取自 Atom 的 babeljs:coffeescript:typescript 智能轉 es5 庫.mp4",
    "ext": ".mp4",
    "category": "樹莓派"
  },
  {
    "type": "video",
    "content": "",
    "intent": "memory_leakDetector",
    "title": "【YFMemoryLeakDetector】人人都能理解的 iOS 記憶體泄露檢測工具類",
    "order": 2,
    "local_video_path": "videos/樹莓派/【YFMemoryLeakDetector】人人都能理解的 iOS 記憶體泄露檢測工具類.mp4",
    "ext": ".mp4",
    "category": "樹莓派"
  },
  {
    "type": "video",
    "content": "",
    "intent": "sinopia_npm",
    "title": "【玩轉樹莓派】使用 sinopia 搭建私有 npm 伺服器",
    "order": 3,
    "local_video_path": "videos/樹莓派/【玩轉樹莓派】使用 sinopia 搭建私有 npm 伺服器.mp4",
    "ext": ".mp4",
    "category": "樹莓派"
  },
  {
    "type": "video",
    "content": "",
    "intent": "frp_ip",
    "title": "【小技巧解決大問題】使用 frp 突破阿裡雲主機無彈性公網 IP 不能用作 Web 伺服器的限制",
    "order": 4,
    "local_video_path": "videos/樹莓派/【小技巧解決大問題】使用 frp 突破阿裡雲主機無彈性公網 IP 不能用作 Web 伺服器的限制.mp4",
    "ext": ".mp4",
    "category": "樹莓派"
  },
  {
    "type": "video",
    "content": "",
    "intent": "luajit_macos",
    "title": "【LuaJIT版】從零開始在 macOS 上配置 Lua 開發環境",
    "order": 5,
    "local_video_path": "videos/Lua/【LuaJIT版】從零開始在 macOS 上配置 Lua 開發環境.mp4",
    "ext": ".mp4",
    "category": "Lua"
  },
  {
    "type": "video",
    "content": "",
    "intent": "lua_macos",
    "title": "【最新版】從零開始在 macOS 上配置 Lua 開發環境",
    "order": 6,
    "local_video_path": "videos/Lua/【最新版】從零開始在 macOS 上配置 Lua 開發環境.mp4",
    "ext": ".mp4",
    "category": "Lua"
  },
  {
    "type": "video",
    "content": "",
    "intent": "app_future",
    "title": "關於混合應用開發的未來的一些思考",
    "order": 7,
    "local_video_path": "videos/Lua/關於混合應用開發的未來的一些思考.mp4",
    "ext": ".mp4",
    "category": "Lua"
  },
  {
    "type": "video",
    "content": "",
    "intent": "google_bug",
    "title": "記錄我發現的第一個關於 Google 的 Bug",
    "order": 8,
    "local_video_path": "videos/Lua/記錄我發現的第一個關於 Google 的 Bug.mp4",
    "ext": ".mp4",
    "category": "Lua"
  },
  {
    "type": "video",
    "content": "",
    "intent": "tip_rest",
    "title": "【樹莓派自動化應用實例】整點提醒自己休息五分鐘",
    "order": 9,
    "local_video_path": "videos/frp/【樹莓派自動化應用實例】整點提醒自己休息五分鐘.mp4",
    "ext": ".mp4",
    "category": "frp"
  },
  {
    "type": "video",
    "content": "",
    "intent": "frp_anywhere",
    "title": "藉助 frp 隨時隨地訪問自己的樹莓派",
    "order": 10,
    "local_video_path": "videos/frp/藉助 frp 隨時隨地訪問自己的樹莓派.mp4",
    "ext": ".mp4",
    "category": "frp"
  }
]

參考文章


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 瞭解事務和鎖 事務:保持邏輯數據一致性與可恢復性,必不可少的利器。 鎖:多用戶訪問同一資料庫資源時,對訪問的先後次序許可權管理的一種機制,沒有他事務或許將會一塌糊塗,不能保證數據的安全正確讀寫。 死鎖:是資料庫性能的重量級殺手之一,而死鎖卻是不同事務之間搶占數據資源造成的。 不懂的聽上去,挺神奇的,懂 ...
  • 前言: 操作資料庫時候難免會因為“大意”而誤操作,需要快速恢復的話通過備份來恢復是不太可能的,因為需要還原和binlog差來恢復,等不了,很費時。這裡先說明下因為Delete 操作的恢復方法:主要還是通過binlog來進行恢復,前提是binlog_format必須是Row格式,否則只能通過備份來恢復 ...
  • 1. 首先要在實例級別啟用FILESTREAM,打開Sql Server Configuration Manager視窗,雙擊需要設置的SQL SERVER實例進行設置。 2. 需要更改 SQL SERVER 實例的 FILESTREAM 訪問級別,執行以下代碼,並重啟 SQL SERVER 服務: ...
  • [20171206]rman與truncate.txt--//昨天下班在回家的路上,突然想起以前遇到的問題,就是truncate表後,rman做備份時會備份多少truncate表的信息,--//當時在itpub上,還存在討論,就是rman會備份空block嗎?參考鏈接:http://www.itpu ...
  • 待續 ...
  • 一,工程圖。 二,代碼。 ViewController.m ...
  • weex旨在“一次撰寫,多端使用”,意思是,用weex寫的頁面,不論是Android還是iOS甚至web端都可以使用,這樣的話就可以極大的降低開發成本, weex其實就是寫的一個類似於h5的頁面(js編寫),寫完之後將vue文件編譯、部署到Nginx伺服器上(Nginx伺服器後面會講到),這時候在... ...
  • android studio報下圖中的這個錯誤的解決辦法: 解決辦法: 1、刪除掉下圖中標記的2個文件夾 2、將下圖標記的文件的文件名重命名,把最後的尾碼.lock去掉,因為加上了這個尾碼,所以提示找不到cache.properties 這個文件 3、點擊try again即可解決 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...