UNPKG

zoro-cli

Version:

https://github.com/vuejs/vue-cli

217 lines (203 loc) 6.6 kB
const axios = require('axios') const internalIp = require('internal-ip') const chalk = require('chalk') const { info, warn, error } = require('zoro-cli-util/logger') const path = require('path') const url = require('url') const { ajax: ajaxMap } = require('./data') const pkg = require('../package.json') const { readPortSync } = require('../script/port') const options = require('../project.config') // 代理项目的 .js/.css 的文件到本地服务器 const regFile = new RegExp( `(fonts|img|dist|www|(${pkg.name}\\/\\d+\\.\\d+\\.\\d+))` ) const regJsCss = /\.(css|js)(\?.*)?$/ const regImg = /\.(png|jpe?g|gif|webp)(\?.*)?$/ const regMedia = /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/ const regFont = /\.(woff2?|eot|ttf|otf)(\?.*)?$/i const ip = internalIp.v4.sync() // port // port = pkg.scripts.dev.match(/\d{4,}/) // port = port ? port[0] : 8000 const port = readPortSync() info(`local server at port ${port}`) info() module.exports = { summary: 'a rule to hack response', *beforeSendRequest(requestDetail) { // see http://anyproxy.io/cn/#beforesendrequest const { requestOptions } = requestDetail const urlInfo = url.parse(requestOptions.path) const pathname = urlInfo.pathname // referer info const { Referer } = requestOptions.headers let refererInfo let refererHostname if (Referer) { refererInfo = url.parse(Referer) refererHostname = refererInfo.hostname } let body let header = {} // mock const mockData = ajaxMap[pathname] if (mockData) { const { filepath, mockResponse } = mockData // 请求代理 try { if (typeof mockResponse === 'function') { body = mockResponse(requestOptions) } else { body = mockResponse } body = JSON.stringify(body) info(`delegate ${pathname} to ${filepath}`) info() } catch (err) { error(chalk.yellow(`failed to delegate ${pathname} to ${filepath}`)) } } if ( refererHostname !== ip && refererHostname !== 'localhost' && refererHostname !== '127.0.0.1' ) { // console.log(refererInfo) // hmr const hmrMatch = urlInfo.path.match( /\/(info|xhr_streaming|eventsource|xhr)(\?t=\d*?)?$/ ) if (hmrMatch) { // hmr 代理 urlInfo.protocol = 'http' urlInfo.hostname = ip urlInfo.port = port urlInfo.pathname = '/sockjs-node/info' const newUrl = url.format(urlInfo) yield axios .get(newUrl) .then(obj => { info(`delegate ${pathname} to ${newUrl}`) info() // just let the request fail, do not support hmr now body = obj.data // body = JSON.stringify(obj.data) header = { ...header, 'Access-Control-Allow-Credentials': true, 'Content-Type': 'application/json; charset=UTF-8', } if (refererInfo) { header['Access-Control-Allow-Origin'] = `${ refererInfo.protocol }//${refererInfo.host}` } }) .catch(err => { warn(`failed to delegate ${pathname} to ${newUrl}`) error(err.toString()) }) } else if ( regFile.test(pathname) && (regJsCss.test(pathname) || regImg.test(pathname) || regMedia.test(pathname) || regFont.test(pathname)) ) { // 文件代理 const pathInfo = path.parse(pathname) const ext = pathInfo.ext let filename = pathInfo.base // console.log(filename) // 处理 render 路径 if (pathname.indexOf('www') !== -1) { const reg = /([\w-]+?)-(\w+?)\./ filename = filename.replace(reg, '$1.') } // 处理资源文件夹 let folder = '' if (regImg.test(pathname)) { folder = options.outputImgDir || 'img' } else if (regMedia.test(pathname)) { folder = options.outputMediaDir || 'media' } else if (regFont.test(pathname)) { folder = options.outputFontsDir || 'fonts' } // 拼接本地文件地址 let newUrl = '' if (folder) { newUrl = `http://${ip}:${port}/${folder}/${filename}` } else { newUrl = `http://${ip}:${port}/${filename}` } yield axios .get(newUrl, { // files are received as binary data responseType: 'arraybuffer', }) .then(obj => { info(`delegate ${pathname} to ${newUrl}`) info() body = obj.data // CORS if (regFont.test(pathname)) { header = { ...header, // ...obj.headers, 'Transfer-Encoding': 'chunked', 'Access-Control-Allow-Origin': '*', 'Content-Type': `font/${ext.slice(1)}`, } } }) .catch(err => { warn(`failed to delegate ${pathname} to ${newUrl}`) error(err.toString()) // dev 环境不 extract js, 所以将 js 文件映射为空文件 if (ext === '.js') { body = 'var anyproxy_js_empty = true;' header = { 'Content-Type': 'application/javascript; charset=utf-8', ...header, } } // dev 环境不 extract css, 所以将 css 文件映射为空文件 if (ext === '.css') { body = '.anyproxy_css_empty{--empty:true;}' header = { 'Content-Type': 'text/css', ...header, } } }) } } if (body) { requestDetail.response = { statusCode: 200, header, body, } } return requestDetail }, *beforeSendResponse(requestDetail, responseDetail) { // see http://anyproxy.io/cn/#beforesendresponse if (requestDetail.url === 'http://httpbin.org/user-agent') { const newResponse = responseDetail.response newResponse.body += '- AnyProxy Hacked!' yield new Promise(resolve => { setTimeout(() => { // delay resolve({ response: newResponse }) }, 5000) }) } }, /* eslint-disable-next-line no-unused-vars */ beforeDealHttpsRequest(requestDetail) { // see http://anyproxy.io/cn/#beforedealhttpsrequest return Promise.resolve(true) }, }