没有不值得去解决的问题,也没有不值得去学习的技术!

基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),调整默认字符集为:utf8mb4,接口响应格式的调整,空数组自动转换为空对象,在接口应用中收集请求日志消息(1个请求对应1条日志消息)至数据库,且实现日志功能的相应接口:日志列表(设置数据过滤器以启用筛选器处理)、日志详情(二)

在开发环境中,执行数据库迁移命令失败:1071 Specified key was too long; max key length is 767 bytes

Yii2 Advanced 实战系列:RESTful API + RPC 服务 + 国际化 + 日志与测试

新建 api 目录、配置和环境、测试、Vagrant 等的支持。

(1) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),新建api目录、配置和环境、测试、Vagrant等的支持

(2) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),实现模型分层:数据层、逻辑层,明确公共目录、应用、模块的继承、引用关系

在 Postman 中,GET http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/users ,200响应,message为简体中文

(3) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),实现 RESTful Web 服务,支持国际化(动态地设置目标语言,默认为简体中文)

运行测试,获取详细的输出,可看到一步一步的行为报告,符合预期

(4) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),在 api 的 tests 目录中准备用户相关操作的一些自动化测试的样例(API 测试),确保应用程序在改变或增加新的功能时不会影响现有的功能

在 Postman 中,GET http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/logs?filter[level]=4&filter[category][like]=api\behaviors\RequestLogBehavior&filter[prefix][like]=app-api&filter[log_time][gte]=1528090828&filter[log_time][lte]=1529564924.6648 ,200响应,空数组已经被自动转换为空对象,以保证字段格式的统一,GET http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/logs/3

(5) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),调整默认字符集为:utf8mb4,接口响应格式的调整,空数组自动转换为空对象,在接口应用中收集请求日志消息(1个请求对应1条日志消息)至数据库,且实现日志功能的相应接口:日志列表(设置数据过滤器以启用筛选器处理)、日志详情

在开发环境中,执行数据库迁移命令失败:1071 Specified key was too long; max key length is 767 bytes

(6) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),调整默认字符集为:utf8mb4,接口响应格式的调整,空数组自动转换为空对象,在接口应用中收集请求日志消息(1个请求对应1条日志消息)至数据库,且实现日志功能的相应接口:日志列表(设置数据过滤器以启用筛选器处理)、日志详情(二)

浏览 user 表数据,status、updated_at 已经更新

(7) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),实现 ActiveRecord 的软删除,生成 ActiveQuery,自定义查询类

执行数据库迁移命令,查看数据库表 user 结构,符合预期

(8) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),实现 ActiveRecord 的软删除,生成 ActiveQuery,自定义查询类(二)

在 Postman 中 POST 请求,http://api.github-shuijingwan-yii2-app-advanced.localhost/v1/users ,输入格式:application/json

(9) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),application/x-www-form-urlencoded 和 multipart/form-data 输入格式,默认支持,新增 application/json 输入格式的支持

打开 Windows PowerShell,执行 init 命令并选择 dev 作为环境,api应用所需环境配置文件自动生成

(10) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建远程过程调用应用(实现基于 Hprose 2.0 for PHP 的 RPC 服务端),新建 rpc 目录、配置和环境、测试、Vagrant等的支持

出现以上原因是因为 Windows 下 nginx php 环境,不支持并发的原因,当同时访问多个域名,并且同时指向你本地服务的时候,就不支持并发了。nginx.conf 里面 对不同 server 修改 fastcgi_pass 的端口号,启动多个 php-cgi。

(11) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建远程过程调用应用(实现基于 Hprose 2.0 for PHP 的 RPC 服务端),在 rpc 目录中实现 页面 的相应 RPC 服务,且在 api 目录中的 API 实现 RPC 客户端

执行数据库迁移,查看表结构,基于 Gii 重新生成模型文件

(12) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,UUID 的实现

由于日志消息是存储于 MySQL 的 log 表中,在生产环境中,累积了大量的数据,log 表的数据长度已经达到 数百 GB ,因此,决定基于控制台命令行实现日志消息的定时删除,开发环境的 log 表的数据长度为 14.64 GB

(13) 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,日志消息的自动定时删除

1、在开发环境中,执行数据库迁移命令失败:1071 Specified key was too long; max key length is 767 bytes,如图17

在开发环境中,执行数据库迁移命令失败:1071 Specified key was too long; max key length is 767 bytes
图17

[root@45fdb670c7c4 /]# php /sobey/www/pcs-api/yii migrate --interactive=0
Yii Migration Tool (based on Yii v2.0.15.1)

Total 1 new migration to be applied:
        m180620_105204_update_table_options_to_log

*** applying m180620_105204_update_table_options_to_log
    > execute SQL: ALTER TABLE {{%user}} CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ...Exception: SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
The SQL being executed was: ALTER TABLE `pa_user` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci (/sobey/www/pcs-api/vendor/yiisoft/yii2/db/Schema.php:664)
#0 /sobey/www/pcs-api/vendor/yiisoft/yii2/db/Command.php(1263): yii\db\Schema->convertException(Object(PDOException), 'ALTER TABLE `pa...')
#1 /sobey/www/pcs-api/vendor/yiisoft/yii2/db/Command.php(1075): yii\db\Command->internalExecute('ALTER TABLE `pa...')
#2 /sobey/www/pcs-api/vendor/yiisoft/yii2/db/Migration.php(219): yii\db\Command->execute()
#3 /sobey/www/pcs-api/console/migrations/m180620_105204_update_table_options_to_log.php(19): yii\db\Migration->execute('ALTER TABLE {{%...')
#4 /sobey/www/pcs-api/vendor/yiisoft/yii2/db/Migration.php(114): m180620_105204_update_table_options_to_log->safeUp()
#5 /sobey/www/pcs-api/vendor/yiisoft/yii2/console/controllers/BaseMigrateController.php(725): yii\db\Migration->up()
#6 /sobey/www/pcs-api/vendor/yiisoft/yii2/console/controllers/BaseMigrateController.php(199): yii\console\controllers\BaseMigrateController->migrateUp('m180620_105204_...')
#7 [internal function]: yii\console\controllers\BaseMigrateController->actionUp(0)
#8 /sobey/www/pcs-api/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#9 /sobey/www/pcs-api/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
#10 /sobey/www/pcs-api/vendor/yiisoft/yii2/console/Controller.php(148): yii\base\Controller->runAction('', Array)
#11 /sobey/www/pcs-api/vendor/yiisoft/yii2/base/Module.php(528): yii\console\Controller->runAction('', Array)
#12 /sobey/www/pcs-api/vendor/yiisoft/yii2/console/Application.php(180): yii\base\Module->runAction('migrate', Array)
#13 /sobey/www/pcs-api/vendor/yiisoft/yii2/console/Application.php(147): yii\console\Application->runAction('migrate', Array)
#14 /sobey/www/pcs-api/vendor/yiisoft/yii2/base/Application.php(386): yii\console\Application->handleRequest(Object(yii\console\Request))
#15 /sobey/www/pcs-api/yii(23): yii\base\Application->run()
#16 {main}
*** failed to apply m180620_105204_update_table_options_to_log (time: 0.008s)


0 from 1 migrations were applied.

Migration failed. The rest of the migrations are canceled.


2、在开发环境中的数据库中运行SQL,报错:#1071 – Specified key was too long; max key length is 767 bytes,如图18

在开发环境中的数据库中运行SQL,报错:#1071 - Specified key was too long; max key length is 767 bytes
图18

3、如果使用的是utf8mb4,并且在长度超过191个字符的varchar列上有唯一索引,则需要打开innodb_large_prefix以允许索引中的较大列,因为utf8mb4需要比utf8或latin1更多的存储空间。如果启用innodb_large_prefix(默认值),则对于使用DYNAMIC或COMPRESSED行格式的InnoDB表,索引键前缀限制为3072个字节。如果innodb_large_prefix被禁用,则任何行格式的表的索引键前缀限制为767字节。在本地环境执行迁移命令成功,是因为本地环境的MySQL版本为5.7.19(MySQL 5.7.7 默认启用innodb_large_prefix,Innodb_large_prefix在MySQL 5.7.7中已弃用,并将在未来版本中删除。),而开发环境为 5.6.16,查看网址:https://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html ,如图19

如果使用的是utf8mb4,并且在长度超过191个字符的varchar列上有唯一索引,则需要打开innodb_large_prefix以允许索引中的较大列,因为utf8mb4需要比utf8或latin1更多的存储空间。
图19

4、阿里云RDS的参数配置,启用Innodb_large_prefix,如图20

阿里云RDS的参数配置,启用Innodb_large_prefix
图20

5、在开发环境中的数据库中运行SQL,成功,如图21

在开发环境中的数据库中运行SQL,成功
图21

ALTER DATABASE `pcs-api-dev` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci
ALTER TABLE pa_user ROW_FORMAT=DYNAMIC
ALTER TABLE pa_user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci


注:一些数据库还可能需要运行


set global innodb_file_format = BARRACUDA;


6、编辑数据库迁移文件,\console\migrations\m180620_105204_update_table_options_to_log.php

<?php
 
use yii\db\Migration;
 
/**
 * Class m180620_105204_update_table_options_to_log
 */
class m180620_105204_update_table_options_to_log extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function safeUp()
    {
        $tableOptions = null;
        if ($this->db->driverName === 'mysql') {
            // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
            $tableOptions = 'CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB';
            $this->execute('ALTER TABLE {{%user}} ROW_FORMAT=DYNAMIC');
            $this->execute('ALTER TABLE {{%user}} CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
            $this->execute('ALTER TABLE {{%log}} ROW_FORMAT=DYNAMIC');
            $this->execute('ALTER TABLE {{%log}} CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
        }
 
        $this->addCommentOnTable('{{%user}}', '用户', $tableOptions);
        $this->addCommentOnTable('{{%log}}', '日志', $tableOptions);
    }
 
    /**
     * {@inheritdoc}
     */
    public function safeDown()
    {
        echo "m180620_105204_update_table_options_to_log cannot be reverted.\n";
 
        return false;
    }
 
    /*
    // Use up()/down() to run migration code without a transaction.
    public function up()
    {
 
    }
 
    public function down()
    {
        echo "m180620_105204_update_table_options_to_log cannot be reverted.\n";
 
        return false;
    }
    */
}
 

7、配置请求日志允许记录的请求方法,主要是忽略 GET 请求的日志,编辑 \api\config\params.php

<?php
return [
    'adminEmail' => 'admin@example.com',
    'requestLog' => [
        'allowMethod' => ['POST', 'PUT', 'DELETE'], //请求日志允许记录的请求方法
    ],
];

8、在 Postman 中,GET http://api.pcs-api.localhost/v1/logs?login_id=e56db1b43546a110431ac38409ed8e9e&login_tid=49117dc410c491af0de08f2948aecd8f&page=2


{
    "code": 10000,
    "message": "获取日志列表成功",
    "data": {
        "items": [
            {
                "id": 21,
                "level": 4,
                "category": "api\\behaviors\\RequestLogBehavior::afterRequest",
                "log_time": 1530000329.6175,
                "prefix": "[app-api][/v1/config-column-users/1][8]",
                "message": {
                    "url": "/v1/config-column-users/1",
                    "request_query_params": {
                        "id": "1",
                        "login_id": "e56db1b43546a110431ac38409ed8e9e",
                        "login_tid": "49117dc410c491af0de08f2948aecd8f"
                    },
                    "request_body_params": {
                        "users": [
                            {
                                "user_pic": "https://cmcconsole.chinamcloud.com/user_pic/1800000005_13281105967_1529552309.png",
                                "user_mobile": "13281105967",
                                "id": "8",
                                "user_nick": "13281105967",
                                "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
                                "user_type": "1",
                                "update_time": "2018-06-26 15:37:52",
                                "add_time": "2018-04-26 10:05:28",
                                "login_name": "13281105967",
                                "user_token": "fb46626f0e71e423ca8ab4c750620a85",
                                "is_open": "1",
                                "user_email": "13281105967@chinamcloud.com"
                            },
                            {
                                "id": "299",
                                "group_id": "015ce30b116ce86058fa6ab4fea4ac63",
                                "login_name": "test11",
                                "user_token": "670d30e8d2d1f994fc0788d4ce95e0f3",
                                "user_nick": "test11",
                                "user_pic": "https://cmcconsole.chinamcloud.com/imgs/default_header.png",
                                "user_mobile": "",
                                "user_email": "",
                                "is_open": "1",
                                "add_time": "2018-05-15 18:47:43",
                                "update_time": "2018-05-18 15:08:11",
                                "user_type": "2"
                            }
                        ]
                    },
                    "user_id": "8",
                    "$_SERVER": {
                        "HTTP_ACCEPT_LANGUAGE": "zh-CN,zh;q=0.9",
                        "HTTP_ACCEPT": "application/json; version=0.0; cookie=enable",
                        "HTTP_HOST": "api.pcs-api.localhost",
                        "REMOTE_ADDR": "127.0.0.1",
                        "REQUEST_URI": "/v1/config-column-users/1",
                        "REQUEST_METHOD": "PUT",
                        "CONTENT_TYPE": "application/x-www-form-urlencoded; charset=utf-8"
                    }
                }
            },
            {
                "id": 22,
                "level": 4,
                "category": "api\\behaviors\\RequestLogBehavior::afterRequest",
                "log_time": 1530000396.3784,
                "prefix": "[app-api][/v1/config-columns][8]",
                "message": {
                    "url": "/v1/config-columns",
                    "request_query_params": {
                        "login_id": "e56db1b43546a110431ac38409ed8e9e",
                        "login_tid": "49117dc410c491af0de08f2948aecd8f"
                    },
                    "request_body_params": {
                        "status": "1",
                        "code": "wxbj",
                        "name": "无线北京"
                    },
                    "user_id": "8",
                    "$_SERVER": {
                        "HTTP_ACCEPT_LANGUAGE": "zh-CN,zh;q=0.9",
                        "HTTP_ACCEPT": "application/json; version=0.0; cookie=enable",
                        "HTTP_HOST": "api.pcs-api.localhost",
                        "REMOTE_ADDR": "127.0.0.1",
                        "REQUEST_URI": "/v1/config-columns",
                        "REQUEST_METHOD": "POST",
                        "CONTENT_TYPE": "application/x-www-form-urlencoded; charset=utf-8"
                    }
                }
            },
            {
                "id": 23,
                "level": 4,
                "category": "api\\behaviors\\RequestLogBehavior::afterRequest",
                "log_time": 1530000418.5957,
                "prefix": "[app-api][/v1/config-columns/3][8]",
                "message": {
                    "url": "/v1/config-columns/3",
                    "request_query_params": {
                        "id": "3",
                        "login_id": "e56db1b43546a110431ac38409ed8e9e",
                        "login_tid": "49117dc410c491af0de08f2948aecd8f"
                    },
                    "request_body_params": {},
                    "user_id": "8",
                    "$_SERVER": {
                        "HTTP_ACCEPT_LANGUAGE": "zh-CN,zh;q=0.9",
                        "HTTP_ACCEPT": "application/json; version=0.0; cookie=enable",
                        "HTTP_HOST": "api.pcs-api.localhost",
                        "REMOTE_ADDR": "127.0.0.1",
                        "REQUEST_URI": "/v1/config-columns/3",
                        "REQUEST_METHOD": "DELETE",
                        "CONTENT_TYPE": "application/json; charset=utf-8"
                    }
                }
            }
        ],
        "_links": {
            "self": {
                "href": "http://api.pcs-api.localhost/v1/logs?login_id=e56db1b43546a110431ac38409ed8e9e&login_tid=49117dc410c491af0de08f2948aecd8f&page=2"
            },
            "first": {
                "href": "http://api.pcs-api.localhost/v1/logs?login_id=e56db1b43546a110431ac38409ed8e9e&login_tid=49117dc410c491af0de08f2948aecd8f&page=1"
            },
            "prev": {
                "href": "http://api.pcs-api.localhost/v1/logs?login_id=e56db1b43546a110431ac38409ed8e9e&login_tid=49117dc410c491af0de08f2948aecd8f&page=1"
            }
        },
        "_meta": {
            "totalCount": 23,
            "pageCount": 2,
            "currentPage": 2,
            "perPage": 20
        }
    }
}


基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),调整默认字符集为:utf8mb4,接口响应格式的调整,空数组自动转换为空对象,在接口应用中收集请求日志消息(1个请求对应1条日志消息)至数据库,且实现日志功能的相应接口:日志列表(设置数据过滤器以启用筛选器处理)、日志详情 基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),实现 ActiveRecord 的软删除,生成 ActiveQuery,自定义查询类

PHP / Yii2 老项目维护与长期技术支持

如果你的 Yii2 项目已经上线,但遇到原开发离职、Bug 长期无人修复、接口不稳定、性能下降、代码难以接手等问题,可以联系我做一次远程技术排查。

适合以下情况:
✅ Yii2 老项目无人维护
✅ 后台管理系统 Bug 修复
✅ RESTful API 接口排查
✅ 小功能迭代与历史代码接手
✅ MySQL / Redis / Nginx 性能问题
✅ 长期远程兼职维护

可先从一次小问题开始:
✅ 线上报错排查
✅ 接口异常分析
✅ 慢查询与性能瓶颈定位
✅ 代码结构初步评估
✅ 部署环境与日志检查

如需咨询,请联系我,并注明:Yii2 维护咨询

联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com

评论

2 条对“基于 yiisoft/yii2-app-advanced,在 GitHub 上新建仓库 yii2-app-advanced,新建接口应用(实现 RESTful 风格的 Web Service 服务的 API),调整默认字符集为:utf8mb4,接口响应格式的调整,空数组自动转换为空对象,在接口应用中收集请求日志消息(1个请求对应1条日志消息)至数据库,且实现日志功能的相应接口:日志列表(设置数据过滤器以启用筛选器处理)、日志详情(二)”的回复

  1. […] 20、参考:阿里云RDS的参数配置,启用Innodb_large_prefix 。编辑 config/database.php,修改 ‘engine’ => null, 为 ‘engine’ => ‘InnoDB’,。再次执行数据库迁移,报错。SQLSTATE[42S01]: Base table or view already exists: 1050 Table ‘failed_jobs’ already exists。在数据库中删除掉所有表后,重新执行迁移。不再报错。 […]

  2. […] Reference:Parameter configuration of Alibaba Cloud RDS, enable InnoDB_Large_Prefix . Edit config/database.php, modifyEngine=>null, forEngine=>innodb,. Execute the database […]

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理