1. 程式人生 > 實用技巧 >內網代理上網環境下,搭建vue-element-admin環境

內網代理上網環境下,搭建vue-element-admin環境

內網代理上網環境下,搭建vue-element-admin環境

公司(外包)開發機器一直只能通過http代理上網,我覺得領導們給這個小水管只是為了方便查查資料。

但是作為面向網路開發的碼農,下載github開源專案、下載maven依賴包等都是需要網路。git下載通過配置git的http代理就可以實現。maven下載jar包因為網路問題總是超時,為此我還特地本機搭建了一個nexus的maven私有倉庫。

最近專案組準備重構十幾年前的老專案,甲方提供了一個nexus私有倉庫(終於不用使用自己的小水管下jar包了)。甲方準備使用vue構建前端專案。但是實際使用發現,網路環境是很大的障礙。這就產生了本篇筆記了。如何在內網環境下搭建vue(本篇特質vue-element-admin)的開發環境。

初始想法

因為某種原因,國內訪問npm就是很慢。所以大家一般都會使用淘寶映象cnpm。這裡就不詳細寫如何配置了,建議通過alias的方式使用,不要直接安裝cnpm,據說會有問題。本機因為網路太差,直接使用npm config set registry https://registry.npm.taobao.org 設定全域性倉庫地址。

當然配置淘寶映象還不行,因為本機是使用http代理上網,所以還要配置npm的http代理。

#設定網路代理的命令
npm config set proxy="http://192.168.2.1:8080"

一切準備就緒,執行npm install時發現,理論可行,實際因為網速問題,無法執行。只能另尋他法。

使用私有倉庫

因為甲方提供了一個nexus私有倉庫。之前有了解到,nexus不僅能作為maven倉庫,也可以做npm代理倉庫。登陸私有倉庫管理頁面找到名字叫npm-group的倉庫,複製倉庫地址。

執行命令npm config set registry http://192.168.2.1/nexus/repository/npm-group/ 使用私有倉庫映象。(因為私有倉庫在內網,需要取消npm的網路代理npm config delete proxy

git問題

以為這就完了?還沒有!

在vue-element-admin專案目錄執行npm install發現速度確實很快。但是會報錯!

24294 verbose stack Error: exited with error code: 128
24294 verbose stack     at ChildProcess.<anonymous> (D:\Programs\node-v10.16.3-win-x64\node-global\node_modules\npm\node_modules\pacote\lib\util\finished.js:12:19)
24294 verbose stack     at emitTwo (events.js:126:13)
24294 verbose stack     at ChildProcess.emit (events.js:214:7)
24294 verbose stack     at maybeClose (internal/child_process.js:925:16)
24294 verbose stack     at Socket.stream.socket.on (internal/child_process.js:346:11)
24294 verbose stack     at emitOne (events.js:116:13)
24294 verbose stack     at Socket.emit (events.js:211:7)
24294 verbose stack     at Pipe._handle.close [as _onclose] (net.js:557:12)
24295 verbose cwd E:\dzg\vue-element-admin
24296 verbose Windows_NT 6.1.7601
24297 verbose argv "C:\\Program Files\\nodejs\\node.exe" "D:\\Programs\\node-v10.16.3-win-x64\\node-global\\node_modules\\npm\\bin\\npm-cli.js" "install"
24298 verbose node v8.11.3
24299 verbose npm  v6.14.8
24300 error Error while executing:
24300 error D:\Programs\Git\bin\git.EXE ls-remote -h -t git://github.com/adobe-webplatform/eve.git
24300 error
24300 error fatal: unable to connect to github.com:
24300 error github.com[0: 52.74.223.119]: errno=No error
24300 error
24300 error
24300 error exited with error code: 128
24301 verbose exit [ 1, true ]

看提示內容,是從github拉取時網路超時。因為本機已經給git配置了代理。應該可以正常拉取的。

問題在於這個拉取的地址是git://開頭,看來git配置的http代理無法代理git://協議。

這也是可以解決的。一般情況下,github公開的倉庫拉取時可以使用https協議。如果我將拉取的地址改成https協議的是不是就可以正常拉取了呢?

那就要找到呼叫git命令的地方,修改引數。控制檯日誌顯示報錯的地方是D:\Programs\node-v10.16.3-win-x64\node-global\node_modules\npm\node_modules\pacote\lib\util\finished.js:12:19

開啟檔案如下。

'use strict'

const BB = require('bluebird')

module.exports = function (child, hasExitCode = false) {
  return BB.fromNode(function (cb) {
    child.on('error', cb)
    child.on(hasExitCode ? 'close' : 'end', function (exitCode) {
      if (exitCode === undefined || exitCode === 0) {
        cb()
      } else {
        let err = new Error('exited with error code: ' + exitCode)
        cb(err)
      }
    })
  })
}

好像沒有啥有用資訊。不過在這個檔案所在的資料夾裡面,發現了一個git.js的檔案。

開啟一看發現裡面封裝了對git的操作。搜尋ls-remote關鍵字。

找到程式碼塊:

function revs (repo, opts) {
  opts = optCheck(opts)
  const cached = REVS.get(repo)
  if (cached) {
    return BB.resolve(cached)
  }
  return pinflight(`ls-remote:${repo}`, () => {
    return spawnGit(['ls-remote', '-h', '-t', repo], {
      env: gitEnv()
    }, opts).then((stdout) => {
      return stdout.split('\n').reduce((revs, line) => {
        const split = line.split(/\s+/, 2)
        if (split.length < 2) { return revs }
        const sha = split[0].trim()
        const ref = split[1].trim().match(/(?:refs\/[^/]+\/)?(.*)/)[1]
        if (!ref) { return revs } // ???
        if (ref.endsWith(CARET_BRACES)) { return revs } // refs/tags/x^{} crap
        const type = refType(line)
        const doc = { sha, ref, type }

        revs.refs[ref] = doc
        // We can check out shallow clones on specific SHAs if we have a ref
        if (revs.shas[sha]) {
          revs.shas[sha].push(ref)
        } else {
          revs.shas[sha] = [ref]
        }

        if (type === 'tag') {
          const match = ref.match(/v?(\d+\.\d+\.\d+(?:[-+].+)?)$/)
          if (match && semver.valid(match[1], true)) {
            revs.versions[semver.clean(match[1], true)] = doc
          }
        }

        return revs
      }, { versions: {}, 'dist-tags': {}, refs: {}, shas: {} })
    }, err => {
      err.message = `Error while executing:\n${GITPATH} ls-remote -h -t ${repo}\n\n${err.stderr}\n${err.message}`
      throw err
    }).then(revs => {
      if (revs.refs.HEAD) {
        const HEAD = revs.refs.HEAD
        Object.keys(revs.versions).forEach(v => {
          if (v.sha === HEAD.sha) {
            revs['dist-tags'].HEAD = v
            if (!revs.refs.latest) {
              revs['dist-tags'].latest = revs.refs.HEAD
            }
          }
        })
      }
      REVS.set(repo, revs)
      return revs
    })
  })
}

猜測第一個引數repo應該是倉庫地址。在函式第一行加上repo = repo.replace('git://','https://');。儲存,再次執行npm install

23712 verbose stack Error: Command failed: git clone --mirror -q git://github.com/adobe-webplatform/eve.git D:\Programs\node-v10.16.3-win-x64\node-cache\_cacache\tmp\git-clone-8ab7d4f1\.git --config core.longpaths=true
23712 verbose stack warning: templates not found in C:\Users\XC85E2~1.DIN\AppData\Local\Temp\pacote-git-template-tmp\git-clone-cf99ec69
23712 verbose stack fatal: unable to connect to github.com:
23712 verbose stack github.com[0: 52.74.223.119]: errno=No error
23712 verbose stack
23712 verbose stack
23712 verbose stack     at ChildProcess.exithandler (child_process.js:275:12)
23712 verbose stack     at emitTwo (events.js:126:13)
23712 verbose stack     at ChildProcess.emit (events.js:214:7)
23712 verbose stack     at maybeClose (internal/child_process.js:925:16)
23712 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:209:5)
23713 verbose cwd E:\dzg\vue-element-admin
23714 verbose Windows_NT 6.1.7601
23715 verbose argv "C:\\Program Files\\nodejs\\node.exe" "D:\\Programs\\node-v10.16.3-win-x64\\node-global\\node_modules\\npm\\bin\\npm-cli.js" "install"
23716 verbose node v8.11.3
23717 verbose npm  v6.14.8
23718 error code 128
23719 error Command failed: git clone --mirror -q git://github.com/adobe-webplatform/eve.git D:\Programs\node-v10.16.3-win-x64\node-cache\_cacache\tmp\git-clone-8ab7d4f1\.git --config core.longpaths=true
23719 error warning: templates not found in C:\Users\XC85E2~1.DIN\AppData\Local\Temp\pacote-git-template-tmp\git-clone-cf99ec69
23719 error fatal: unable to connect to github.com:
23719 error github.com[0: 52.74.223.119]: errno=No error
23720 verbose exit [ 1, true ]

還是報錯,不過和前面的錯不一樣。看來這麼改沒問題,只是還有地方沒改到。最後檢視git.js中其他的git命令。按照前面的方法調整。

調整後的git.js

'use strict'

const BB = require('bluebird')

const cp = require('child_process')
const execFileAsync = BB.promisify(cp.execFile, {
  multiArgs: true
})
const finished = require('./finished')
const LRU = require('lru-cache')
const optCheck = require('./opt-check')
const osenv = require('osenv')
const path = require('path')
const pinflight = require('promise-inflight')
const promiseRetry = require('promise-retry')
const uniqueFilename = require('unique-filename')
const which = BB.promisify(require('which'))
const semver = require('semver')
const inferOwner = require('infer-owner')

const GOOD_ENV_VARS = new Set([
  'GIT_ASKPASS',
  'GIT_EXEC_PATH',
  'GIT_PROXY_COMMAND',
  'GIT_SSH',
  'GIT_SSH_COMMAND',
  'GIT_SSL_CAINFO',
  'GIT_SSL_NO_VERIFY'
])

const GIT_TRANSIENT_ERRORS = [
  'remote error: Internal Server Error',
  'The remote end hung up unexpectedly',
  'Connection timed out',
  'Operation timed out',
  'Failed to connect to .* Timed out',
  'Connection reset by peer',
  'SSL_ERROR_SYSCALL',
  'The requested URL returned error: 503'
].join('|')

const GIT_TRANSIENT_ERROR_RE = new RegExp(GIT_TRANSIENT_ERRORS)

const GIT_TRANSIENT_ERROR_MAX_RETRY_NUMBER = 3

function shouldRetry (error, number) {
  return GIT_TRANSIENT_ERROR_RE.test(error) && (number < GIT_TRANSIENT_ERROR_MAX_RETRY_NUMBER)
}

const GIT_ = 'GIT_'
let GITENV
function gitEnv () {
  if (GITENV) { return GITENV }
  const tmpDir = path.join(osenv.tmpdir(), 'pacote-git-template-tmp')
  const tmpName = uniqueFilename(tmpDir, 'git-clone')
  GITENV = {
    GIT_ASKPASS: 'echo',
    GIT_TEMPLATE_DIR: tmpName
  }
  Object.keys(process.env).forEach(k => {
    if (GOOD_ENV_VARS.has(k) || !k.startsWith(GIT_)) {
      GITENV[k] = process.env[k]
    }
  })
  return GITENV
}

let GITPATH
try {
  GITPATH = which.sync('git')
} catch (e) {}

module.exports.clone = fullClone
function fullClone (repo, committish, target, opts) {
  repo = repo.replace('git://','https://');
  opts = optCheck(opts)
  console.log(target)
  const gitArgs = ['clone', '--mirror', '-q', repo, path.join(target, '.git')]
  if (process.platform === 'win32') {
    gitArgs.push('--config', 'core.longpaths=true')
  }
  return execGit(gitArgs, { cwd: target }, opts).then(() => {
    return execGit(['init'], { cwd: target }, opts)
  }).then(() => {
    return execGit(['checkout', committish || 'HEAD'], { cwd: target }, opts)
  }).then(() => {
    return updateSubmodules(target, opts)
  }).then(() => headSha(target, opts))
}

module.exports.shallow = shallowClone
function shallowClone (repo, branch, target, opts) {
  repo = repo.replace('git://','https://');
  opts = optCheck(opts)
  const gitArgs = ['clone', '--depth=1', '-q']
  if (branch) {
    gitArgs.push('-b', branch)
  }
  gitArgs.push(repo, target)
  if (process.platform === 'win32') {
    gitArgs.push('--config', 'core.longpaths=true')
  }
  return execGit(gitArgs, {
    cwd: target
  }, opts).then(() => {
    return updateSubmodules(target, opts)
  }).then(() => headSha(target, opts))
}

function updateSubmodules (localRepo, opts) {
  const gitArgs = ['submodule', 'update', '-q', '--init', '--recursive']
  return execGit(gitArgs, {
    cwd: localRepo
  }, opts)
}

function headSha (repo, opts) {
  opts = optCheck(opts)
  return execGit(['rev-parse', '--revs-only', 'HEAD'], { cwd: repo }, opts).spread(stdout => {
    return stdout.trim()
  })
}

const CARET_BRACES = '^{}'
const REVS = new LRU({
  max: 100,
  maxAge: 5 * 60 * 1000
})
module.exports.revs = revs
function revs (repo, opts) {
  repo = repo.replace('git://','https://');
  opts = optCheck(opts)
  const cached = REVS.get(repo)
  if (cached) {
    return BB.resolve(cached)
  }
  return pinflight(`ls-remote:${repo}`, () => {
    return spawnGit(['ls-remote', '-h', '-t', repo], {
      env: gitEnv()
    }, opts).then((stdout) => {
      return stdout.split('\n').reduce((revs, line) => {
        const split = line.split(/\s+/, 2)
        if (split.length < 2) { return revs }
        const sha = split[0].trim()
        const ref = split[1].trim().match(/(?:refs\/[^/]+\/)?(.*)/)[1]
        if (!ref) { return revs } // ???
        if (ref.endsWith(CARET_BRACES)) { return revs } // refs/tags/x^{} crap
        const type = refType(line)
        const doc = { sha, ref, type }

        revs.refs[ref] = doc
        // We can check out shallow clones on specific SHAs if we have a ref
        if (revs.shas[sha]) {
          revs.shas[sha].push(ref)
        } else {
          revs.shas[sha] = [ref]
        }

        if (type === 'tag') {
          const match = ref.match(/v?(\d+\.\d+\.\d+(?:[-+].+)?)$/)
          if (match && semver.valid(match[1], true)) {
            revs.versions[semver.clean(match[1], true)] = doc
          }
        }

        return revs
      }, { versions: {}, 'dist-tags': {}, refs: {}, shas: {} })
    }, err => {
      err.message = `Error while executing:\n${GITPATH} ls-remote -h -t ${repo}\n\n${err.stderr}\n${err.message}`
      throw err
    }).then(revs => {
      if (revs.refs.HEAD) {
        const HEAD = revs.refs.HEAD
        Object.keys(revs.versions).forEach(v => {
          if (v.sha === HEAD.sha) {
            revs['dist-tags'].HEAD = v
            if (!revs.refs.latest) {
              revs['dist-tags'].latest = revs.refs.HEAD
            }
          }
        })
      }
      REVS.set(repo, revs)
      return revs
    })
  })
}

// infer the owner from the cwd git is operating in, if not the
// process cwd, but only if we're root.
// See: https://github.com/npm/cli/issues/624
module.exports._cwdOwner = cwdOwner
function cwdOwner (gitOpts, opts) {
  const isRoot = process.getuid && process.getuid() === 0
  if (!isRoot || !gitOpts.cwd) { return Promise.resolve() }

  return BB.resolve(inferOwner(gitOpts.cwd).then(owner => {
    gitOpts.uid = owner.uid
    gitOpts.gid = owner.gid
  }))
}

module.exports._exec = execGit
function execGit (gitArgs, gitOpts, opts) {
  opts = optCheck(opts)
  return BB.resolve(cwdOwner(gitOpts, opts).then(() => checkGit(opts).then(gitPath => {
    return promiseRetry((retry, number) => {
      if (number !== 1) {
        opts.log.silly('pacote', 'Retrying git command: ' + gitArgs.join(' ') + ' attempt # ' + number)
      }
      return execFileAsync(gitPath, gitArgs, mkOpts(gitOpts, opts)).catch((err) => {
        if (shouldRetry(err, number)) {
          retry(err)
        } else {
          throw err
        }
      })
    }, opts.retry != null ? opts.retry : {
      retries: opts['fetch-retries'],
      factor: opts['fetch-retry-factor'],
      maxTimeout: opts['fetch-retry-maxtimeout'],
      minTimeout: opts['fetch-retry-mintimeout']
    })
  })))
}

module.exports._spawn = spawnGit
function spawnGit (gitArgs, gitOpts, opts) {
  opts = optCheck(opts)
  return BB.resolve(cwdOwner(gitOpts, opts).then(() => checkGit(opts).then(gitPath => {
    return promiseRetry((retry, number) => {
      if (number !== 1) {
        opts.log.silly('pacote', 'Retrying git command: ' + gitArgs.join(' ') + ' attempt # ' + number)
      }
      const child = cp.spawn(gitPath, gitArgs, mkOpts(gitOpts, opts))

      let stdout = ''
      let stderr = ''
      child.stdout.on('data', d => { stdout += d })
      child.stderr.on('data', d => { stderr += d })

      return finished(child, true).catch(err => {
        if (shouldRetry(stderr, number)) {
          retry(err)
        } else {
          err.stderr = stderr
          throw err
        }
      }).then(() => {
        return stdout
      })
    }, opts.retry)
  })))
}

module.exports._mkOpts = mkOpts
function mkOpts (_gitOpts, opts) {
  const gitOpts = {
    env: gitEnv()
  }
  const isRoot = process.getuid && process.getuid() === 0
  // don't change child process uid/gid if not root
  if (+opts.uid && !isNaN(opts.uid) && isRoot) {
    gitOpts.uid = +opts.uid
  }
  if (+opts.gid && !isNaN(opts.gid) && isRoot) {
    gitOpts.gid = +opts.gid
  }
  Object.assign(gitOpts, _gitOpts)
  return gitOpts
}

function checkGit (opts) {
  if (opts.git) {
    return BB.resolve(opts.git)
  } else if (!GITPATH) {
    const err = new Error('No git binary found in $PATH')
    err.code = 'ENOGIT'
    return BB.reject(err)
  } else {
    return BB.resolve(GITPATH)
  }
}

const REFS_TAGS = 'refs/tags/'
const REFS_HEADS = 'refs/heads/'
const HEAD = 'HEAD'
function refType (ref) {
  return ref.indexOf(REFS_TAGS) !== -1
    ? 'tag'
    : ref.indexOf(REFS_HEADS) !== -1
      ? 'branch'
      : ref.endsWith(HEAD)
        ? 'head'
        : 'other'
}

再次執行npm install。這下成功結束。可以愉快的npm run dev了。

結語

本人是java開發,習慣了maven的簡單和方便。對npm這種配置了倉庫還要從git獲取資訊的方式很不理解。或許是為了更加靈活吧?

最後,希望每個遇到問題的人都能願意瞭解其原理,找到解決方法。