美文网首页
项目部署多环境

项目部署多环境

作者: 不困于情 | 来源:发表于2019-01-16 15:16 被阅读103次

    背景:之前项目都是在本地开发,迭代到日常环境,一次次的迭代之后,要发布到预发和正式,才有了此文。

    文章结构:


    文章结构

    1. 前端-管理端

    以下内容基于cli2.0

    2.1 环境区分

    2.1.1 axios的封装

    talk is cheap this is the code:

    文件:@/utils/request.js

    import axios from 'axios'
    import store from '@/store'
    import { getToken } from '@/utils/auth'
    import Cookies from 'js-cookie'
    
    // create an axios instance
    const service = axios.create({
      baseURL: process.env.BASE_API, // api 的 base_url
      timeout: 5000 // request timeout
      // withCredentials: true
    })
    
    // request interceptor
    service.interceptors.request.use(
      config => {
        // Do something before request is sent
        if (window.localStorage.getItem('token')) {
        // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
          config.headers['X-Token'] = window.localStorage.getItem('token')
        }
        // if (Cookies.get('_traceid_')) {
        //   config.headers['X-Trace'] = Cookies.get('_traceid_')
        // }
        return config
      },
      error => {
        // Do something with request error
        console.log(error) // for debug
        Promise.reject(error)
      }
    )
    
    // response interceptor
    service.interceptors.response.use(
      response => response,
      /**
       * 下面的注释为通过在response里,自定义code来标示请求状态
       * 当code返回如下情况则说明权限有问题,登出并返回到登录页
       * 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
       * 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
       */
      // response => {
      //   const res = response.data
      //   if (res.code !== 20000) {
      //     Message({
      //       message: res.message,
      //       type: 'error',
      //       duration: 5 * 1000
      //     })
      //     // 50008:非法的token; 50012:其他客户端登录了;  50014:Token 过期了;
      //     if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
      //       // 请自行在引入 MessageBox
      //       // import { Message, MessageBox } from 'element-ui'
      //       MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
      //         confirmButtonText: '重新登录',
      //         cancelButtonText: '取消',
      //         type: 'warning'
      //       }).then(() => {
      //         store.dispatch('FedLogOut').then(() => {
      //           location.reload() // 为了重新实例化vue-router对象 避免bug
      //         })
      //       })
      //     }
      //     return Promise.reject('error')
      //   } else {
      //     return response.data
      //   }
      // },
      error => {
        console.log('err' + error) // for debug
        return Promise.reject(error)
      }
    )
    
    export default service
    

    注释已经很清楚了,一句话来说就是封装了一个axios请求。最重要的三部分:

    • 请求拦截
    • 响应拦截
    • 基础的api_url

    之后我们在统一在一个api的文件夹中书写请求,像这样:

    import request from '@/utils/request'
    
    export function loginByUsername(username, password) {
      const data = {
        username,
        password
      }
      return request({
        url: '/login/login',
        method: 'post',
        data
      })
    }
    
    export function logout() {
      return request({
        url: '/login/logout',
        method: 'post'
      })
    }
    

    2.1.2 构建

    要确定安装了cross-env

    npm install cross-env 
    

    1、先准备三个环境的文件,分别为:

    • dev.env.js //日常环境
    • pre.env.js // 预发环境
    • prod.env.js //生产环境

    内容为:

    'use strict'
    module.exports = {
      NODE_ENV: '"production"', 
      ENV_CONFIG: '"prod"', 
      BASE_API: '"https://api.yoururl.com"' //填你的base_api
    }
    

    2、之后我们在webpack.prod.conf.js中配置一下env:

    const env = require('../config/' + process.env.env_config + '.env')
    console.log(env) //可以打印一下看看是否出错
    

    plugins中的内容不变:

    new webpack.DefinePlugin({
          'process.env': env
    }),
    

    3、这样配置就结束了,我们还需要设置一下打包的命令,在package.json中:

    "build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
    

    打开终端,输入命令npm run build:prod来测试一下吧

    2. 前端-手机端

    2.1 环境区分

    同上管理端,不再累述。

    2.2 钉钉登录

    2.2.1 ddlogin.html页面

    钉钉免登是一个单独的页面,我们放在根目录下面,ddlogin.html。

    需要后端配合写两个接口,代码注释中有。具体后端内容参考钉钉开发者文档。

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
        <meta charset="gbk" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <meta content="yes" name="apple-mobile-web-app-capable" />
        <meta content="black" name="apple-mobile-web-app-status-bar-style" />
        <meta content="telephone=no" name="format-detection" />
        <meta content="yes" name="apple-touch-fullscreen" />
        <meta
          name="viewport"
          content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no"
        />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0"
        />
    
        <title>加载中...</title>
        <script type="text/javascript"></script>
        <script type="text/javascript" src="/static/js/zepto.min.js"></script>
        <script
          type="text/javascript"
          src="https://g.alicdn.com/dingding/open-develop/1.6.9/dingtalk.js"
        ></script>
      </head>
    
      <body>
        <script type="text/javascript">
           var host = <%=htmlWebpackPlugin.options.ddloginapi %>;
           var configURL = host + '/dingding/config';//获取配置
           var loginURL = host + '/dingding/login';//登录
    
    
          $(function() {
            // alert("111");
            function getConfig(callback) {
              $.ajax({
                url: configURL,
                type: "get",
                data: {
                  url: location.href
                },
                success: function(data, status, xhr) {
                  callback(data);
                },
                error: function(xhr, errorType, error) {
                  console.log(error);
                }
              });
            }
    
            getConfig(function(data) {
              var _config = data;
    
              dd.config({
                agentId: _config.agentid,
                corpId: _config.corpId,
                timeStamp: _config.timeStamp,
                nonceStr: _config.nonceStr,
                signature: _config.signature,
                jsApiList: [
                  "runtime.info",
                  "biz.contact.choose",
                  "device.notification.confirm",
                  "device.notification.alert",
                  "device.notification.prompt",
                  "biz.ding.post",
                  "biz.util.openLink"
                ]
              });
    
              dd.ready(function() {
                dd.runtime.permission.requestAuthCode({
                  corpId: _config.corpId,
                  onSuccess: function(info) {
                    $.ajax({
                      url: loginURL,
                      data: {
                        code: info.code
                      },
                      type: "POST",
                      success: function(data, status, xhr) {
                        if (data.success) {
                          window.localStorage.setItem(
                            "userName",
                            data.sysUser.name
                          );
                          window.localStorage.setItem("userId", data.sysUser.id);
                          window.localStorage.setItem("token", data.token);
                          location.href = '/?rand='+Math.random();
                        } else {
                          alert("登录失败");
                        }
                      },
                      error: function(xhr, errorType, error) {
                        alert("login error");
                      }
                    });
                  },
                  onFail: function(err) {
                    alert("onfail" + JSON.stringify(err));
                  }
                });
              });
    
              dd.error(function(err) {
                alert("dd error: " + JSON.stringify(err));
              });
            });
          });
        </script>
      </body>
    </html>
    
    

    2.2.2 页面中的环境区分

    由于这个免登页面是个单页面,所以我们单独拿出来区分一下环境。做法是把域名抽离出来,通过htmlWebpackPlugin来获取到值。页面代码中:

    var host = <%=htmlWebpackPlugin.options.ddloginapi %>;
    

    接下来是需要我们配置的。在webpack.prod.conf.js中

    new HtmlWebpackPlugin({
          filename: config.build.ddlogin,
          template: 'ddlogin.html',
          inject: false,
          title: '加载中...',
          ddloginapi: env.BASE_API, //根据不同的BASE_API获取到值
          minify: {
            removeComments: true,
            collapseWhitespace: true,
            removeAttributeQuotes: true
          }
    })
    

    3. 小程序

    小程序三个版本分别对应为:

    envVersion: 'develop', //开发版

    envVersion: 'trial', //体验版

    envVersion: 'release', //正式版

    所以可通过以下代码来区分环境。

    function version(){
      console.log('envVersion', __wxConfig.envVersion);
      let version = __wxConfig.envVersion;
      switch (version)
      {
        case 'develop':
          return 'https://测试版环境域名';
          break;
        case 'trial':
          return 'https://体验版环境域名';
          break;
        case 'release':
          return 'https://线上环境域名';
          break;
        default:
          return 'https://测试版环境域名';
      }
    }
     
    //调用
    version();
    

    一个示例

    在根目录下创建config.js,内容为:

    let host = version();
    
    function version() {
      console.log('envVersion', __wxConfig.envVersion);
      let version = __wxConfig.envVersion;
      switch (version) {
        case 'develop':
          return 'https://dev-cod-api.hzhengji.cn';
          break;
        case 'trial':
          return 'https://pre-cod-api.hzhengji.cn';
          break;
        case 'release':
          return 'https://cod-api.hzhengji.cn';
          break;
        default:
          return 'https://dev-cod-api.hzhengji.cn';
      }
    }
    
    let config = {
        host,
        login: `${host}/wechat/login`,  //登录
        upload: `${host}/answer/head/upload`,   //上传到oss
    };
    module.exports = config;
    

    后端

    后端使用的是springboot,分离环境比较简单,三个配置文件active一下就可以了,不再累述。网上一搜一大把。

    相关文章

      网友评论

          本文标题:项目部署多环境

          本文链接:https://www.haomeiwen.com/subject/kbemdqtx.html