Skip to content

20. 在托管服务上部署客户端/服务器应用程序

本文将概述如何将我们开发的客户端/服务器应用程序部署到 OVH 服务器 [https://www.ovh.com/fr/] 上。在其他托管服务商上的部署过程应该大同小异。我们只是想说明,我们的应用程序非常适合这种部署方式。

20.1. 服务器部署

本文所涉及的 OVH 托管服务为基础托管套餐:

  1. PHP 7.3 运行环境;
  2. MySQL 数据库管理系统;
  3. [Redis] 服务器;

第三点要求我们修改税费计算服务器的第 14 版。

Image

我们需要修改:

  • 配置文件 [1]
  • [AdminDataController] [CalculerImpotController] 控制器,以适应没有 [Redis] 服务器的情况;

[config.json] 文件的修改如下:


{
    "databaseFilename": "Config/database.json",
    "corsAllowed": false,
    "redisAvailable":false,
    "rootDirectory": "/.../www/apps/impot/serveur-php7",
    "relativeDependencies": [
 
        "/Entities/BaseEntity.php",
        ...
        "/Controllers/AdminDataController.php"
    ],
    "absoluteDependencies": [
        "/.../vendor/autoload.php",
        "/.../vendor/predis/predis/autoload.php"
    ],
    "users": [
        {
            "login": "admin",
            "passwd": "admin"
        }
    ],
    ...
}

注释

  • 第 4 行:我们引入了一个布尔变量 [redisAvailable],用于指示是否可以访问 [Redis] 服务器;
  • 第 5、13、14 行:绝对路径将会发生变化;

[database.json] 文件的更改如下:


{
    "dsn": "mysql:host=...;dbname=...",
    "id": "...",
    "pwd": "...",
    "tableTranches": "dbimpots_tbtranches",
    "colLimites": "limites",
    "colCoeffR": "coeffr",
    "colCoeffN": "coeffn",
    "tableConstantes": "dbimpots_tbconstantes",
    "colPlafondQfDemiPart": "plafondQfDemiPart",
    ...
}

注释

  • 第2–4行:数据库名称及其所有者的凭据将发生变化;

[AdminDataController] 的演变如下:


<?php
 
namespace Application;
 
// symfony dependencies
use \Symfony\Component\HttpFoundation\Response;
use \Symfony\Component\HttpFoundation\Request;
use \Symfony\Component\HttpFoundation\Session\Session;
// layer alias [dao]
use \Application\ServerDaoWithSession as ServerDaoWithRedis;
 
class AdminDataController implements InterfaceController {
 
  // $config is the application configuration
  // traitement d'une requête Request
  // session and can modify it
  // $infos is additional information specific to each controller
  // renders an array [$statusCode, $état, $content, $headers]
  public function execute(
    array $config,
    Request $request,
    Session $session,
    array $infos = NULL): array {
 
    // you must have a single parameter GET
    $method = strtolower($request->getMethod());
    ...
 
    // we can work
    // Redis
    if ($config["redisAvailable"]) {
      \Predis\Autoloader::register();
      ...
    } else {
      try {
        // retrieve tax data from the database
        $dao = new ServerDaoWithRedis($config["databaseFilename"], NULL);
        // taxAdminData
        $taxAdminData = $dao->getTaxAdminData();
      } catch (\Throwable $ex) {
        // it didn't go well
        // return result with error to main controller
        $état = 1051;
        return [Response::HTTP_INTERNAL_SERVER_ERROR, $état,
          ["réponse" => utf8_encode($ex->getMessage())], []];
      }
    }
 
    // return result to main controller
    $état = 1000;
    return [Response::HTTP_OK, $état, ["réponse" => $taxAdminData], []];
  }
 
}

评论

  • 第 31 行:现在检查是否存在 [Redis] 服务器;
  • 第 32–34 行:如果存在,则执行前面的全部代码;
  • 第 35–46 行:否则,从数据库中检索税务机关数据;

同样需要税务机关数据的 [CalculerImpotController] 控制器也以相同的方式进行更新。

就这样。部署到 OVH 服务器时使用了 FTP。我们将以下内容上传到了 OVH:

  • [vuejs-14-without-redis] 版本;
  • [vendor] 文件夹,其中包含 [vuejs-14-without-redis] 服务器的所有依赖项;

FTP传输完成后,我们使用以下SQL脚本为服务器生成了必要的表:


-- phpMyAdmin SQL Dump
-- version 4.8.5
-- https://www.phpmyadmin.net/
--
-- Host: localhost:3306
-- Generation Time: Oct 12, 2019 at 07:45 AM
-- Server version: 5.7.24
-- PHP Version: 7.2.11
 
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
 
 
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
 
--
-- Table structure for table `dbimpots_tbconstantes`
--
 
CREATE TABLE `dbimpots_tbconstantes` (
  `id` int(11) NOT NULL,
  `plafondQfDemiPart` decimal(10,2) NOT NULL,
  `plafondRevenusCelibatairePourReduction` decimal(10,2) NOT NULL,
  `plafondRevenusCouplePourReduction` decimal(10,2) NOT NULL,
  `valeurReducDemiPart` decimal(10,2) NOT NULL,
  `plafondDecoteCelibataire` decimal(10,2) NOT NULL,
  `plafondDecoteCouple` decimal(10,2) NOT NULL,
  `plafondImpotCelibatairePourDecote` decimal(10,2) NOT NULL,
  `plafondImpotCouplePourDecote` decimal(10,2) NOT NULL,
  `abattementDixPourcentMax` decimal(10,2) NOT NULL,
  `abattementDixPourcentMin` decimal(10,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
--
-- Dumping data for table `dbimpots_tbconstantes`
--
 
INSERT INTO `dbimpots_tbconstantes` (`id`, `plafondQfDemiPart`, `plafondRevenusCelibatairePourReduction`, `plafondRevenusCouplePourReduction`, `valeurReducDemiPart`, `plafondDecoteCelibataire`, `plafondDecoteCouple`, `plafondImpotCelibatairePourDecote`, `plafondImpotCouplePourDecote`, `abattementDixPourcentMax`, `abattementDixPourcentMin`) VALUES
(8, '1551.00', '21037.00', '42074.00', '3797.00', '1196.00', '1970.00', '1595.00', '2627.00', '12502.00', '437.00');
 
-- --------------------------------------------------------
 
--
-- Table structure for table `dbimpots_tbtranches`
--
 
CREATE TABLE `dbimpots_tbtranches` (
  `id` int(11) NOT NULL,
  `limites` decimal(10,2) NOT NULL,
  `coeffR` decimal(10,2) NOT NULL,
  `coeffN` decimal(10,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
--
-- Dumping data for table `dbimpots_tbtranches`
--
 
INSERT INTO `dbimpots_tbtranches` (`id`, `limites`, `coeffR`, `coeffN`) VALUES
(36, '9964.00', '0.00', '0.00'),
(37, '27519.00', '0.14', '1394.96'),
(38, '73779.00', '0.30', '5798.00'),
(39, '156244.00', '0.41', '13913.69'),
(40, '0.00', '0.45', '20163.45');
 
--
-- Indexes for dumped tables
--
 
--
-- Indexes for table `dbimpots_tbconstantes`
--
ALTER TABLE `dbimpots_tbconstantes`
  ADD PRIMARY KEY (`id`);
 
--
-- Indexes for table `dbimpots_tbtranches`
--
ALTER TABLE `dbimpots_tbtranches`
  ADD PRIMARY KEY (`id`);
 
--
-- AUTO_INCREMENT for dumped tables
--
 
--
-- AUTO_INCREMENT for table `dbimpots_tbconstantes`
--
ALTER TABLE `dbimpots_tbconstantes`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=9;
 
--
-- AUTO_INCREMENT for table `dbimpots_tbtranches`
--
ALTER TABLE `dbimpots_tbtranches`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=41;
COMMIT;
 
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

完成上述所有操作后,我们将 [config.json, database.json] 文件适配到了新环境。

20.2. [Vue.js] 客户端的部署

已决定将 [Vue.js] 客户端部署到 URL [http://machine/apps/impot/client-vuejs/]。这导致了以下变更:

[VSCode] [工作区] 的根目录下我们创建了以下 [vue.config.js] 文件:

Image

[vue.config.js] 文件内容如下:


// vue.config.js
module.exports = {
  // l'URL de service du client [vuejs] du serveur de calcul de l'impôt
  publicPath: '/apps/impot/client-vuejs/'
}

[router.js] [3] 文件也已进行修改:


// imports
import Vue from 'vue'
import VueRouter from 'vue-router'
...
 
// plugin de routage
Vue.use(VueRouter)
 
// les routes de l'application
const routes = [
  ...
]
 
// le routeur
const router = new VueRouter({
  // les routes
  routes,
  // le mode d'affichage des URL
  mode: 'history',
  // l'URL de base de l'application
  base: '/apps/impot/client-vuejs/'
})
 
// vérification des routes
router.beforeEach((to, from, next) => {
  ...
})
 
// export du router
export default router

注释

  • 第 21 行:URL 基址已更改;

[config.js] 文件修改如下:


// utilisation de la bibliothèque [axios]
const axios = require('axios');
// timeout des requêtes HTTP
axios.defaults.timeout = 5000;
// la base des URL du serveur de calcul de l'impôt
// le schéma [https] pose des problèmes à Firefox parce que le serveur de calcul
// de l'impôt envoie un certificat autosigné. ok avec Chrome et Edge. Safari pas testé.
// avec Firefox c'est possible en demandant l'URL ci-dessous directement et en disant à Firefox
// que vous acceptez le risque d'un certificat non signé. Ensuite le client [vuejs] fonctionnera.
axios.defaults.baseURL = 'http://.../apps/impot/serveur-php7';
// on va utiliser des cookies
axios.defaults.withCredentials = true;
 
// export de la configuration
export default {
  // objet [axios]
  axios: axios,
  // délai maximal d'inactivité de la session : 5 mn = 300 s = 300000 ms
  duréeSession: 300000
}

注释

  • 第10行:输入税费计算服务器的URL;

该项目的生产版本是通过以下 [package.json] 文件中的 [build] 命令生成的 [5]


{
  "name": "vuejs",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve vuejs-22/main.js",
    "build": "vue-cli-service build vuejs-22-ovh-withBootstrapVue/main.js",
    "lint": "vue-cli-service lint"
  },
  ...
}

完成上述操作后,将包含生成的生产版本的 [dist] 文件夹“上传”到 OVH 服务器上的 [/.../apps/impot] 文件夹中,然后将其重命名为 [client-vuejs],以便客户端代码能按计划位于 [/.../apps/impot/client-vuejs/] 文件夹中。 接着,我们在该文件夹中上传了以下 [.htaccess] 文件:


<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /apps/impot/client-vuejs/
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /apps/impot/client-vuejs/index.html [L]
</IfModule>

这是因为此处使用的 OVH 网络服务器是 Apache 服务器。对于其他类型的服务器,请参阅文档 |https://cli.vuejs.org/guide/deployment.html|。

PHP 7 服务器应用程序可在此处进行测试 |此处|

[Vue.js] 客户端可在此处进行测试 |此处|

20.3. 结论

版本 [vuejs-21] 并非必需。 我们已经看到,版本 [vuejs-20] 能够正确处理用户输入的 URL。尽管如此,新版本为用户提供了额外的便利。用户可以通过输入 URL 进行导航,应用程序随后会显示最适合当前状态(即会话)的视图。此外,版本 [vuejs-22] 还改进了应用程序在移动设备上的显示效果。