快速入門vue-cli配置

来源:https://www.cnblogs.com/caideyipi/archive/2018/03/03/8496656.html
-Advertisement-
Play Games

作為一名使用了一段時間Vue.js的新手,相信和不少初入Vue的朋友一樣,都對Vue-cli的配置一知半解。後來通過對webpack的學習,也算是對腳手架的配置有了一定的瞭解,所以也想把這段時間自己的成果分享給大家,希望能和大家一起進步。 有兩點要說明的: 閱讀本文需要瞭解一點點webpack的知識 ...


作為一名使用了一段時間Vue.js的新手,相信和不少初入Vue的朋友一樣,都對Vue-cli的配置一知半解。後來通過對webpack的學習,也算是對腳手架的配置有了一定的瞭解,所以也想把這段時間自己的成果分享給大家,希望能和大家一起進步。

有兩點要說明的:

  1. 閱讀本文需要瞭解一點點webpack的知識,至少要entry,output,module,plugins都是做什麼,以及一些常用的loader和plugins;
  2. 本文使用的是最新版的vue,配置可能會和大家的有所不同,不過差距不會太大,不影響閱讀;

一.起步

先放一張自己整理的簡易腦圖:

Vue-cli有兩個文件——buildconfig:build文件包含了腳手架在開發環境和生產環境下webpack該如何配置。config文件則包含了build文件下webpack具體配置的值。換句話說,build下的webpack配置的值要引入config後才能獲取到。

 

config文件夾下一共有三個文件

  • dev.env.js: 導出開發環境名稱;
  • prod.env.js: 導出生產環境名稱;
  • index.js: 導出不同環境的具體配置;

 

build文件夾下一共有七個文件

  • build.js: 編譯時的入口文件,當執行npm run build時其實就是執行node build/build.js(在package.json中);
  • check-versions.js: 編譯代碼時執行的確認node和npm版本的文件,如果版本不符,則停止編譯;
  • utils.js:這個文件有兩個作用,一是作為vue-loader的配置來使用;另一個是用來給開發環境和生產環境配置loader;
  • vue-loader.conf.js:vue-loader的配置,用在webpack.base.conf.js中;
  • webpack.base.conf.js:vue-cli腳手架的基礎webpack配置,通過與webpack.dev.conf.js和webpack.prod.conf.js兩個配置文件的合併(合併方式我會在下一章來講)來實現“不重覆原則(Don't repeat yourself - DRY),不會在不同的環境中配置相同的代碼
  • webpack.dev.conf.js:開發環境下的webpack的配置;
  • webpack.prod.conf.js:生產環境下的webpack的配置;

二.config文件

1.prod.env.js:

//導出一個對象,對象有一個當前node環境的屬性,值為“production”(生產環境)
module.exports = {  NODE_ENV: '"production"'}

 

2.dev.env.js:
//導出另一個對象,屬性為當前的node環境,值為“development”(開發環境)
const merge = require('webpack-merge')const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {  NODE_ENV: '"development"'})

 

  • 這裡要著重說一下webpack-merge這個包,這個包的作用是來合併兩個配置文件對象並生成一個新的配置文件,有點兒類似於es6的Object.assign()方法。如果合併的過程中遇到衝突的屬性,第二個參數的屬性值會覆蓋第一個參數的屬性值。
  • 前面寫到webpack.base.conf.js與webpack.dev.conf.js和webpack.prod.conf.js的合併也用到了webpack-merge。Vue-cli將一些通用的配置抽出來放在一個文件內(webpack.base.conf.js),在對不同的環境配置不同的代碼,最後使用webpack-merge來進行合併,減少重覆代碼。

關於更多webpack-merge請點擊https://www.npmjs.com/package/webpack-merge  

3.index.js:

index.js作為具體的配置值,我覺得沒必要把代碼貼出來了,大家可以拿上面的的腦圖或者自己項目里的文件來結合我後面要說的代碼來看。

三.build文件

1.check.versions.js:

//chalk 是一個用來在命令行輸出不同顏色文字的包,可以使用chalk.yellow("想添加顏色的文字....")
//來實現改變文字顏色的;
const chalk = require('chalk')

//semver 的是一個語義化版本文件的npm包,其實它就是用來控製版本的;
const semver = require('semver')const packageConfig = require('../package.json')

//一個用來執行unix命令的包
const shell = require('shelljs')

//child_process 是Node.js提供了衍生子進程功能的模塊,execSync()方法同步執行一個cmd命令,
//將返回值的調用toString和trim方法
function exec (cmd) {  
    return require('child_process').execSync(cmd).toString().trim()
}

const versionRequirements = [
  {    name: 'node',

    //semver.clean()方法返回一個標準的版本號,切去掉兩邊的空格,比如semver.clean(" =v1.2.3 ")
    //返回"1.2.3",此外semver還有vaild,satisfies,gt,lt等方法,
    //這裡查看https://npm.taobao.org/package/semver可以看到更多關於semver方法的內容  
    currentVersion: semver.clean(process.version),    
    versionRequirement: packageConfig.engines.node  
  }
]
//shell.which方法是去環境變數搜索有沒有參數這個命令
if (shell.which('npm')) {  
    versionRequirements.push({    
        name: 'npm',
        //執行"npm --version"命令    
        currentVersion: exec('npm --version'),     
        versionRequirement: packageConfig.engines.npm  
    }
)}

//後面這部分代碼就比較好理解了
module.exports = function () {  const warnings = []
  for (let i = 0; i < versionRequirements.length; i++) {    
   const mod = versionRequirements[i] if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
  warnings.push(mod.name + ': ' + chalk.red(mod.currentVersion) + ' should be ' + chalk.green(mod.versionRequirement) ) } } if (warnings.length) { console.log('') console.log(chalk.yellow('To use this template, you must update following to modules:')) console.log() for (let i = 0; i < warnings.length; i++) { const warning = warnings[i] console.log(' ' + warning) } console.log() process.exit(1) }}

2.utils.js:

 

const path = require('path')const config = require('../config')

//這個plugin的作用是將打包後生成的css文件通過link的方式引入到html中,如果不適用這個插件css代碼會
//放到head標簽的style中
const ExtractTextPlugin = require('extract-text-webpack-plugin')

const packageConfig = require('../package.json')

//process.env.NODE_ENV是一個環境變數,它是由webpack.dev/prod.conf.js這兩個文件聲明的;
//這裡的意思是判斷當前是否是開發環境,如果是就把config下index.js文件中build.assetsSubDirectory或
//dev.assetsSubDirectory的值賦給assetsSubDirectory 
exports.assetsPath = function (_path) {  
    const assetsSubDirectory = process.env.NODE_ENV === 'production'    
    ? config.build.assetsSubDirectory    
    : config.dev.assetsSubDirectory  
  //path.posix.join是path.join的一種相容性寫法,它的作用是路徑的拼接,這裡返回的是"static/_path"
  return path.posix.join(assetsSubDirectory, _path
)}
//cssLoaders的作用是導出一個供vue-loader的options使用的一個配置;
exports.cssLoaders = function (options) {  
    options = options || {}
    const cssLoader = {    
        loader: 'css-loader',    
        options: {      
            sourceMap: options.sourceMap    
        }  
    }
    const postcssLoader = {    
        loader: 'postcss-loader',    
        options: {      
            sourceMap: options.sourceMap    
        }  
    }
function generateLoaders (loader, loaderOptions) {    
    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
    if (loader) {     
         loaders.push({        
            loader: loader + '-loader',       
            options: Object.assign({}, loaderOptions, {          
                sourceMap: options.sourceMap        
            })      
        })    
    }
    if (options.extract) {      
        return ExtractTextPlugin.extract({        
            use: loaders,        
            fallback: 'vue-style-loader'      
        })    
    } else {      
        return ['vue-style-loader'].concat(loaders)    
        }  
    }
    return {    
        css: generateLoaders(),    
        postcss: generateLoaders(),    
        less: generateLoaders('less'),    
        sass: generateLoaders('sass', { indentedSyntax: true }),    
        scss: generateLoaders('sass'),    
        stylus: generateLoaders('stylus'),    
        styl: generateLoaders('stylus')  
    }
}

// styleLoaders是用來給webpack提供所有和css相關的loader的配置,它也使用了cssLoaders()方法;
exports.styleLoaders = function (options) {  
    const output = []  const loaders = exports.cssLoaders(options)
    for (const extension in loaders) {    
        const loader = loaders[extension]    
        output.push({      
            test: new RegExp('\\.' + extension + '$'),     
            use: loader    
        })  
    }
  return output
}

//'node-notifier'是一個跨平臺系統通知的頁面,當遇到錯誤時,它能用系統原生的推送方式給你推送信息
exports.createNotifierCallback = () => {  
    const notifier = require('node-notifier')
    return (severity, errors) => {    
        if (severity !== 'error') return
        const error = errors[0]    
        const filename = error.file && error.file.split('!').pop()
        notifier.notify({      
            title: packageConfig.name,      
            message: severity + ': ' + error.name,      
            subtitle: filename || '',     
             icon: path.join(__dirname, 'logo.png')    
        })  
    }
}

 

這裡可能有的朋友不瞭解cssLoaders()和styleLoaders()這兩個方法返回的是個什麼東西,我在這裡簡單的寫一下:

  • cssLoaders方法根據傳進來的參數(options)是否有extract屬性來返回不同的值,如果你看了後面的代碼你就會知道在生產模式下extract屬性為true,開發模式下為false。也就是說,在生產模式下返回的是一個類似於這樣的數組:
ExtractTextPlugin.extract({
    use: ["css-loader","less-loader","sass-loader"...],
    fallback: 'vue-style-loader'
})

 這些css代碼打包以link的方式放到HTML中。當然了,use的值確切的說應該是這樣:

[ { loader: 'css-loader', options: { sourceMap: true } }, { loader: 'less-loader', options: { sourceMap: true } } ]

我為了方便看就簡寫了。

而在開發模式下,cssLoaders返回的是:

["vue-style-loader","css-loader","less-loader","sass-loader"...] //我還是簡寫了
  • styleLoaders方法返回的值就簡單了,它返回的就是webpack中module里常用的配置格式:
[
    {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
    },
    ...
]

 

3.vue-loader.conf.js:

const utils = require('./utils')
const config = require('../config')

//不同環境為isProduction 賦值: 生產環境為true,開發環境為false
const isProduction = process.env.NODE_ENV === 'production'

//不同環境為sourceMapEnabled 賦值: 這裡都為true
const sourceMapEnabled = isProduction  
? config.build.productionSourceMap  
: config.dev.cssSourceMap
//導出vue-loader的配置,這裡我們用了utils文件中的cssLoaders();
module.exports = {  
    loaders: utils.cssLoaders({    
        sourceMap: sourceMapEnabled,    
        extract: isProduction  
    }),  
    cssSourceMap: sourceMapEnabled,
    cacheBusting: config.dev.cacheBusting,

    //transformToRequire的作用是在模板編譯的過程中,編譯器可以將某些屬性,如src轉換為require調用;  
    transformToRequire: {    
        video: ['src', 'poster'],    
        source: 'src',    
        img: 'src',    
        image: 'xlink:href'  
    }
}

 

4.webpack.base.conf.js:  
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')

//resolve這個函數返回的是當前目錄下"../dir"這個文件夾,__dirname指的是當前文件所在路徑
function resolve (dir) {  return path.join(__dirname, '..', dir)}

module.exports = {
    //返回項目的根路徑  
    context: path.resolve(__dirname, '../'),
    //入口文件  
    entry: {    
      app: './src/main.js'  
    },
    //出口文件  
    output: {   
        path: config.build.assetsRoot,    
        filename: '[name].js',    
        publicPath: process.env.NODE_ENV === 'production'      
        ? config.build.assetsPublicPath      
        : config.dev.assetsPublicPath  
    },  
    resolve: {
        //自動解析擴展,比如引入對應的文件,js,vue,json的尾碼名就可以省略了    
        extensions: ['.js', '.vue', '.json'],    
        alias: {
            //精準匹配,使用vue來替代vue/dist/vue.esm.js      
            'vue$': 'vue/dist/vue.esm.js',
            //使用@替代src路徑,當你引入src下的文件是可以使用import XXfrom "@/xx"
            '@': resolve('src'),    
        }  
    },

    //一些loader配置,避免篇幅過長我省略一部分,大家可以看自己的文件 
    module: {    
        rules: [     
            {        
                test: /\.vue$/,        
                loader: 'vue-loader',        
                options: vueLoaderConfig      
            },      
            {        
                test: /\.js$/,        
                loader: 'babel-loader',        
                include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]      
            },      
            ......    
        ]  
    },

    //node里的這些選項是都是Node.js全局變數和模塊,這裡主要是防止webpack註入一些Node.js的東西到vue中  
    node: {    
        setImmediate: false,    
        dgram: 'empty',    
        fs: 'empty',    
        net: 'empty',    
        tls: 'empty',    
        child_process: 'empty'  
    }
}

 

5.webpack.dev.conf.js:

const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')

//一個負責拷貝資源的插件
const CopyWebpackPlugin = require('copy-webpack-plugin')

const HtmlWebpackPlugin = require('html-webpack-plugin')

//一個更友好的展示webpack錯誤提示的插件
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')

//一個自動檢索埠的包
const portfinder = require('portfinder')

const HOST = process.env.HOSTconst PORT = process.env.PORT && Number(process.env.PORT)

const devWebpackConfig = merge(baseWebpackConfig, {  
    module: {    
        rules: utils.styleLoaders({ 
            sourceMap: config.dev.cssSourceMap,
            usePostCSS: true 
        })  
    },  
    
    devtool: config.dev.devtool,
    // devServer的配置大家看文檔就好了 
    devServer: {    
        clientLogLevel: 'warning',    
        historyApiFallback: {      
            rewrites: [        
                { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },      
            ],    
        },    
        hot: true,    
        contentBase: false,   
        compress: true,    
        host: HOST || config.dev.host,    
        port: PORT || config.dev.port,    
        open: config.dev.autoOpenBrowser,   
        overlay: config.dev.errorOverlay      
        ? { warnings: false, errors: true }      
        : false,    
        publicPath: config.dev.assetsPublicPath,    
        proxy: config.dev.proxyTable,    
        quiet: true,    
        watchOptions: {      
            poll: config.dev.poll,    
        }  
    },  
    plugins: [
    
        //還記得之前說的生產環境和開發環境的變數在哪兒定義的嗎?對,就是這裡    
        new webpack.DefinePlugin({      
            process.env: require('../config/dev.env')    
        }),

        //模塊熱替換的插件,修改模塊不需要刷新頁面    
        new webpack.HotModuleReplacementPlugin(),

        //當使用HotModuleReplacementPlugin時,這個插件會顯示模塊正確的相對路徑    
        new webpack.NamedModulesPlugin(),

        //在編譯出錯時,使用NoEmitOnErrorsPlugin來跳過輸出階段,這樣可以確保輸出資源不會包含錯誤
        new webpack.NoEmitOnErrorsPlugin(),   
        new HtmlWebpackPlugin({      
            filename: 'index.html',      
            template: 'index.html',      
            inject: true    
        }),    

        // 將static文件夾和裡面的內容拷貝到開發模式下的路徑,比如static下有個img文件夾,裡面有張圖片
        // 我們可以這樣訪問:localhost:8080/static/img/logo.png    
        new CopyWebpackPlugin([     
            {        
                from: path.resolve(__dirname, '../static'),        
                to: config.dev.assetsSubDirectory,        
                ignore: ['.*']      
            }    
        ])  
    ]
})

//這裡主要是做埠的檢索以及npm run dev後對錯誤的處理,我們可以看這裡使用了前面引入的
//'friendly-errors-webpack-plugin'插件
module.exports = new Promise((resolve, reject) => {
  portfinder.basePort = process.env.PORT || config.dev.port
  portfinder.getPort((err, port) => {
    if (err) {
      reject(err)
    } else {
      // publish the new Port, necessary for e2e tests
      process.env.PORT = port
      // add port to devServer config
      devWebpackConfig.devServer.port = port

      // Add FriendlyErrorsPlugin
      devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
        compilationSuccessInfo: {
          messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
        },
        onErrors: config.dev.notifyOnErrors
        ? utils.createNotifierCallback()
        : undefined
      }))

      resolve(devWebpackConfig)
    }
  })
})

 

關於devServer有兩點要說明一下:

  • contentBase是來告訴伺服器在哪裡提供靜態的內容,這裡我們使用false的原因是使用了“copy-webpack-plugin”插件,不需要使用contentBase了;
  • quiet開啟後(true),除了初始啟動信息之外的任何內容都不會被列印到控制台,即使是webpack 的錯誤或警告在控制台也不可見。不過我們用了'friendly-errors-webpack-plugin'插件,就可以設為true了。

 

6.webpack.prod.conf.js 

經過前面這麼多代碼的分析,其實webpack.prod.conf.js的配置已經很簡單了,大致跟webpack.dev.conf.js的配置方式差不多,就是多了幾個plugins:

  • UglifyJsPlugin是用來壓縮JS代碼
  • optimize-css-assets-webpack-plugin是用來壓縮css代碼
  • HashedModuleIdsPlugin會根據模塊的相對路徑生成一個四位數的hash作為模塊id
  • ModuleConcatenationPlugin可以預編譯所有模塊到一個包中,加快瀏覽器的運行速度
  • CommonsChunkPlugin拆分公共模塊,vue里拆分了vendor,manifest和app三個模塊
  • compression-webpack-plugin gzip壓縮
  • webpack-bundle-analyzer可以查看打包的具體情況,比如打了多少個包,每個包多大等

好了,plugins的介紹到此結束,接下來就是最後一個文件,也是npm run build編譯時的入口文件——build.js了。

同樣的,build.js文件其實也沒什麼可說的了,無非就是執行webpack.prod.conf.js文件,遇到錯誤時在命令行提示。需要註意的是,build.js里引入了“rimraf”的包,它的作用是每次編譯時清空dist文件,避免多次編譯時造成文件夾的重覆和混亂。

四.結尾

到這裡其實關於Vue-cli配置的分析基本結束了,相信瞭解webpack的朋友看起來一定非常簡單,配置主要麻煩的地方在於低耦合導致經常需要來回翻文件才能看懂配置,如果大家結合著文章開頭的腦圖看可能會相對容易些。

一個壞消息是這個文章發佈的時候webpack4.0已經上線了,Vue-cli新版也進入了Beta測試階段,所以這篇文章大家看看就好,瞭解一下思路,馬上配置又會更新的......


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

-Advertisement-
Play Games
更多相關文章
  • 創建對象 第一種:基於Object對象 第二種:對象字面量方式(比較清楚的查找對象包含的屬性及方法) 使用Object構造函數或對象字面量都可以創建對象,但缺點是創建多個對象時,會產生大量的重覆代碼,因此下麵介紹可解決這個問題的創建對象的方法 1、工廠模式 缺點:創建對象交給一個工廠方法來實現,可以 ...
  • 今天終於開始寫代碼了。 希望明天也能恢復更新吧,寒假在家裡實在太過放鬆了,關於寒假,明天拿出時間來好好總結一下,到底幹了些什麼。 用readyState輸出狀態碼是0,未初始化?什麼意思,不太懂…… 問題暫時先留著這裡,應該是很簡單的問題,11點要斷電,不多想了。 大家晚安。 ...
  • 整理自互聯網 整理做隨筆 如有相似純屬抄襲 淺拷貝和深拷貝都是對於JS中的引用類型而言的,淺拷貝就只是複製對象的引用(堆和棧的關係,簡單類型Undefined,Null,Boolean,Number和String是存入堆,直接引用,object array 則是存入桟中,只用一個指針來引用值),如果 ...
  • 零、組織結構 根據引言,作者將全書劃分為四個部分: 一、頁面載入js的最佳方式(開發前準備) 二、改善js代碼的編程技巧(開發中) 三、構建與部署(發佈) 四、發佈後性能檢測與問題追蹤(線上問題優化) 這樣的組織結構也符合我們的開發習慣,首先進入第一部分。 一、JavaScript載入 起因:scr ...
  • 一、什麼是匿名函數 創建一個函數並將它賦值給變數functionName,這種情況下創建的函數,即匿名函數。(函數表達式就是匿名函數) 二、閉包 1.什麼是閉包? 閉包就是能夠讀取其他函數內部變數的函數。 只有函數內部的子函數才能讀取局部變數,因此可以把閉包簡單理解成“定義在一個函數內部的函數”。 ...
  • html部分 版本號 <script src="http://www.jq22.com/jquery/jquery-1.10.2.js"></script> <!DOCTYPE html><html><head><meta charset="UTF-8"><title></title><style> ...
  • JS為每種數據類型都內置很多方法,真的不好記憶,而且有些還容易記混,現整理如下,以便以後查看: 一、String ①charAt()方法用於返回指定索引處的字元。返回的字元是長度為 1 的字元串。 語法:stringObject.charAt(index) index 必需,表示字元串中某個位置的數 ...
  • localStorage - 沒有時間限制的數據存儲 sessionStorage - 針對一個 session 的數據存儲 共同點:sessionStorage、localStorage和cookie都由瀏覽器存儲在本地的數據。 區別: cookie數據始終在同源的http請求中攜帶(即使不需要) ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...