分类: 知识图谱
知识图谱
数据迁移使用规范
目的,为了使命名更具有语义化和可读性,方便维护
以laravel框架为例,按实际操作行为划分
- 添加 删除 修改(主要参考迁移功能,提供的api方法) 对应名称create drop modify
- 2种以上的操作行为,都算修改
- 给单一操作增加后缀,字段 column,索引 index,视图view, 存储过程 ,函数
- 命名重复情况增加版本号 v1.0.0 …
操作表
表字段,标注注释,表索引
创建表
create_xxxx_table.php
删除表
drop_xxxx_table.php
修改表
包含添加删除字段或索引或其他 ,2种以上行为
modify_xxxx_table.php
操作字段
字段名称,字段数据类型,字段注释
添加字段
create_xxxx_table_column.php
删除字段
drop_xxxx_table_column.php
修改字段
包含添加和删除和修改字段,2种以上行为
modify_xxxx_table_column.php
操作索引
操作普通索引,全文索引,空间索引等;
索引优化是业务开发中,修改频率很高的行为,所以需要单独列出来,有很多场景需要,单独的变更索引,而不修改字段
添加索引
create_xxxx_table_index.php
删除索引
drop_xxxx_table_index.php
修改索引
包含添加 删除 修改 和自定义 2种以上行为时
modify_xxxx_table_index.php
单一操作行为的规则,参考上文以此类推。
多次重复行为时增加语义化版本后缀
需要改进
比如第一次业务变更 增加了字段 create_users_table_column.php
第二次业务变更,又要对users表增加字段,则命名为 create_users_table_column_v1.0.0.php
// 转储当前数据库架构并删除所有现有迁移。。。
php artisan schema:dump --prune
Guzzle使用经验总结
调用接口
主要功能,很多sdk都是使用该类库开发
写爬虫抓取页面
项目中应用案例
java的古籍PC网站,该项目无人维护,无法提供书籍数据的接口。分析页面结构和接口使用guzzle库爬取书籍数据,完成数据对接。
在所用请求中共享cookie功能 文档
//创建客户端
$this->client = new Client([
'base_uri' => $this->config['base_uri'],
'timeout' => 20.0,
'cookies' => true, //共享cookie会话
);
//登录
protected function login()
{
$response = $this->client->request('POST', 'XXX', [
'headers' => [
'Accept' => 'application/json'
],
'form_params' => [
'loginName' => $this->config['login_name'],
'loginPassword' => $this->config['login_password']
]
]);
$json = json_decode($response->getBody(), true);
if (isset($json['operateMsg']) && $json['operateMsg'] !== '登录成功!') {
throw new GujiException('原古籍系统账号故障');
}
}
//请求接口数据
protected function request(string $pathUrl, array $param)
{
$this->login(); //首先登录获取Cookies
$response = $this->client->request('POST', $pathUrl, [
'headers' => [
'Accept' => 'application/json'
],
'form_params' => $param
]);
$contents = $response->getBody()->getContents();
$json = json_decode($contents, true);
if (json_last_error() === JSON_ERROR_NONE) {
return $json;
} elseif (json_last_error() == 10) {
//解决json_decode错误Single unpaired UTF-16 surrogate in unicode escape
$contents = \preg_replace('/(?<!\\\)\\\u[a-f0-9]{4}/iu', '', $contents);
$json = \json_decode($contents, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$json = $this->customJsonDecode($contents);
}
return $json;
}
{
throw new GujiException("请求古籍系统接口失败");
}
}
//抓取页面数据
protected function capture(string $pathUrl, array $param = [])
{
$this->login(); //首先登录获取Cookies
$response = $this->client->request('GET', $pathUrl, $param);
if ($response->getStatusCode() == 200) {
//获取页面内容
return $response->getBody()->getContents();
} else {
throw new GujiException("古籍系统故障");
}
}
跟随重定向
https://docs.guzzlephp.org/en/stable/faq.html#how-can-i-track-redirected-requests
https://docs.guzzlephp.org/en/stable/request-options.html#allow-redirects
调用非知名第三方支付系统,前后端分离架构,前端重定向到接口,接口调用第三方支付接口,成功后跟随响应到成功页面
use Illuminate\Support\Facades\Http;
use Psr\Http\Message\UriInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
//Http::withOptions laravel对guzzle的封装,详情看文档
$response = Http::withOptions([
'allow_redirects' => [
'max' => 1,
'on_redirect' => function (
RequestInterface $request,
ResponseInterface $response,
UriInterface $uri
) use ($data) {
//自动跟随重定向响应
header('Location:' . $uri);
},
]
])->asForm()->post($this->config['base_uri'] . '/multipay/h5.do', $data);
如何编写高质量代码
代码质量的评价词
灵活性(flexibility)、可扩展性(extensibility)、可维护性(maintainability)、可读性(readability)、可理解性(understandability)、易修改性(changeability)、可复用(reusability)、可测试性(testability)、模块化(modularity)、高内聚低耦合(high cohesion loose coupling)、高效(high effciency)、高性能(high performance)、安全性(security)、兼容性(compatibility)、易用性(usability)、整洁(clean)、清晰(clarity)、简单(simple)、直接(straightforward)、少即是多(less code is more)、文档详尽(well-documented)、分层清晰(well-layered)、正确性(correctness、bug free)、健壮性(robustness)、鲁棒性(robustness)、可用性(reliability)、可伸缩性(scalability)、稳定性(stability)、优雅(elegant)、好(good)、坏(bad)
面向对象
面向对象和面向过程是编程范式(方法),不局限于编程语言,即使语言不是面向对象的语言。面向过程语言的特点是不支持丰富的面向对象编程特性(继承,多台,封装)。
面向过程风格的代码被组织成了一组方法集合及其数据结构(struct User),方法和数据结构的定义是分开的
面向对象风格的代码被组织成一组类,方法和数据结构被绑定一起,定义在类中。
面向对象编程语言更适用于大规模复杂应用。二进制指令,汇编语言,面向过程语言,是一种计算机思维方式,面向对象是一种人类思维方式,需要对业务建模,将现实的世界的事物,映射为类或对象,将开发者聚焦业务本身,而不是思考如何和机器打交道。
面向过程风格代码转换面向对象风格,规律总结,
函数等于类方法,复用的变量等于类型属性,
滥用geter,setter,违反了封装特性,举例:将购物车列表list可以随意修改,不应该将业务逻辑暴露给上层代码,要封装到方法中。让上层无法随意修改list
封装:通过访问控制语法提供数据访问保护,隐藏内部数据,外部仅能通过类有限的结果访问修改内部数据。调用者无需关心业务的细节,调用就可以了。
抽象:基于interface和abstract语法,更好的实现封装的方法,隐藏实现细节,是封装的具体实现。
继承:获取父类的方法和属性,复用代码,使用时要避免过度继承和高度耦合
多态:基于,父类可以引用子类,支持继承语法,子类可以重写(override)父类中的方法的语法机制实现多态特性。可以基于interface类实现,提高代码扩展性和复用性
面向对象语言的的设计流程,类分析->类设计->实现
思考如何给业务建模,如何将需求翻译为类,如何给类之间建立交互关系,而完成这些工作完全不需要考虑错综复杂的处理流程。
有了类的设计之后,然后再像搭积木一样,按照处理流程,将类组装起来形成整个程序。这种开发模式、思考问题的方式,能让我们在应对复杂程序开发的时候,思路更加清晰
面向对象编程比面向过程编程,更加容易应对大规模复杂程序的开发。但像 Unix、Linux 这些复杂的系统,也都是基于 C 语言这种面向过程的编程语言开发的,你怎么看待这个现象?
取决于需求是业务复杂度,还是技术复杂度
1.面向过程的编程语言不代表不能实现面向对象思想 2.操作系统的复杂相对于业务系统的快速开发迭代是另一个维度复杂,基础系统更看重性能和稳定,而业务系统看重的是维护,复用,拓展。3.操作系统是要频繁跟硬件打交道的,“低级”的语言更快更简洁
接口和抽象类,基于接口而非实现编程
组合优于继承
贫血模型和充血模型
设计模式
随着编程语言的演进,一些设计模式(比如 Singleton)也随之过时,甚至成了反模式,一些则被内置在编程语言中(比如 Iterator),另外还有一些新的模式诞生(比如 Monostate)。
反面模式 明显出现但又低效或是有待优化的设计模式,是用来解决问题的带有共同性的不良方法
场景:数据库连接 日志 在应用中锁定文件 线程池(threadpool)、缓存(cache)、对话框、处理偏好设置和注册表(register)对象
laravel中服务容器注册单例类 simps-swoole使用单例trait来实现单例
管道设计范式
Laravel 中的 Pipeline (管道) — 管道设计范式
在 PHP 中管道( Pipeline (管道) ) 能帮我们做什么?
UML统一建模语言
泛化、实现、关联、聚合、组合、依赖
uml类图符号的作用,以laravel框架的request类 dd($request)结果为示例,“+”表示 public
,“-”表示 private
, “#”表示 protected
,不带符号表示 default
其它
参考教程
Composer使用经验总结
切换国内镜像 composer 加速扩展包—— hirak/prestissimo 中文文档
–ignore-platform-reqs: 忽略 php
, hhvm
, lib-*
和 ext-*
要求并强制安装,就算本地环境不完全要求。平台配置选项可见 platform
文档
举例说明,windows平台的php不支持pcntl扩展,安装laravel-horizon时需要用的该扩展,可以通过指令强制安装
–with-all-dependencies:(-W)
添加所有白名单中的依赖到白名单,包括那些根依赖,
允许升级、降级和删除目前锁定在特定版本的软件包。
composer require packagename:*
不确定当前项目可以使用扩展的哪个版本的时,可以使用require xxx:* 来计算是否有任何版本可以安装
依赖冲突
比如package A 和 B依赖相同的package C,但是版本不同,需要通过github 或packagelist 的composer.json 找到A和B依赖的最低版本C然后卸载C 然后安装适合版本的A和B,这样会自动安装最适合版本C
laravel 如何覆盖composer的 vendor类文件? 适用于需要修改vendor代码的场景
项目和框架运行缓慢
基于composer构建的项目出现过,加载运行缓慢的问题。碰到过旧laravel项目运行php artisan -v 时,命令显示非常慢。运行php artisan server 访问页面响应也很慢。
具体原因未验证,可能是安装依赖时,和运行项目时的php版本不一致,使用低版本安装了依赖,切换了高版本的php。composer安装项目后,会在vendor/bin目录下生成命令文件和缓存之类的,
解决方法,将vendor目录完全删除,然后重新运行composer install ,项目在升级或切换composer版本和php版本之后保险起见需要重新安装依赖
引入本地包
laravel-devstart 本地包的名称,path指定目录 要用基于当前项目路的相对路径,适用于开发扩展包
//设置路径,本质是创建了一个系统软连接
composer config repositories.laravel-devstart path ../../package/laravel-devstart
//引入本地包的master分支
composer require yangliuan/laravel-devstart:dev-master
扩展包开发
安装 Package Builder 包结构创建工具
composer global require overtrue/package-builder
安装项目需要的依赖
修改composer.json
编写异常
编写单元测试
测试扩展包
发布版本到github
自动化测试
参考教程
- 基于 Composer 的 PHP 模块化开发
- PHP 扩展开发检测清单(扩展开发必读)
- Composer 扩展开发:本地运行扩展包
- pds/skeleton PHP 扩展架构规范(扩展开发必…
- [扩展推荐] 使用 Bootpack 来加快你开发扩展…
- 一步步带你开发 Laravel 5.5 扩展包(实战教…
- 手把手教你如何构建一个优秀的开源项目
扩展包版本对应
Laravel旧版本和扩展包对应版本,方便维护旧项目时参考
Laravel版本 | 扩展包版本 |
5.5 | “laravel/horizon”: “2.1” |
5.5 | “barryvdh/laravel-ide-helper”: “2.4.1” |
5.5 | “doctrine/dbal”: “^2.10” |
5.5 | “laravel/passport”: “~4.0” |
5.5 | “laravel/tinker”: “~1.0” |
5.5 | “propaganistas/laravel-phone”: “^4.2” |
5.5 | “barryvdh/laravel-debugbar”: “3.4”, |
5.5 | “filp/whoops”: “~2.0” |
5.5 | “friendsofphp/php-cs-fixer”: “^2.14” 配置文件为.php_cs.dist |
PHP 开发工具扩展包 使用笔记
前置知识
PSR
是 PHP Standard Recommendations
(PHP 推荐标准)的简写,由 PHP FIG 组织制定的 PHP
规范,是 PHP 开发的实践标准。中文文档 例如composer 遵循psr4标准
很多php框架和组件都遵循psr规范,因此要编写遵循行业规范的代码
PHP-CS-Fixer
推荐在项目中安装配置,因为不同的项目php版本和规范不同,依赖的php-cs-fixer的版本也不相同
安装
composer require --dev friendsofphp/php-cs-fixer
项目根目录创建 .php-cs-fixer.php 配置文件(旧版本为.php_cs) 并且将它纳入git版本管理,保证该项目的所有开发人员都使用相同的规范
将缓存文件.php-cs-fixer.cache 添加到.gitignore文件中 (旧版本为.php_cs.cache)
规则和配置文件
点击问号,查看配置工具使用说明
通过规则风格筛选 比如php版本,psr12等
选中需要的规则
点击导出按钮生成规则配置文件
如何使用
手动使用方式 文档
#指定规则运行
$ php php-cs-fixer.phar fix /path/to/project --rules=@PSR12
#框架项目中指定配置文件手动修复,以laravel为例,在项目根目录下执行
$ vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php
#执行结果如下
Loaded config default from ".php-cs-fixer.php".
1) app/Http/Controllers/Admin/CategoryController.php
2) app/Http/Controllers/Admin/HotKeywordsController.php
... 此处省略中间部分输出信息
205) routes/api.php
206) tests/Feature/CommonApiTest.php
Fixed all files in 2.135 seconds, 20.000 MB memory used
php-cs-fixer vscode插件 github
扩展>>安装 ,个人配置项
{
"php-cs-fixer.executablePath": "${extensionPath}/php-cs-fixer.phar",
"php-cs-fixer.onsave": true,
"[php]": {
"editor.defaultFormatter": "junstyle.php-cs-fixer"
},
}
PHPStan
付费替代品vscode 插件 PHP Intelephense 支持代码自动提示,跳转追踪和语法检测 99RMB永久授权
laravel版本 Larastan github 也是基于phpstan开发的
Laravel-ide-helper
安装
composer require --dev barryvdh/laravel-ide-helper
如果需要为模型生成字段,需要安装如下扩展包,参考文章是laravel5.5版本 跟laravel-ide-helper版本有关
laravel-ide-helper”: “^2.10″版本测试会自动安装doctrine/dbal 扩展包
composer require doctrine/dbal
生成配置文件 config目录下会生成ide-helper.php
php artisan vendor:publish --provider="Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider" --tag=config
为Facades生成文档提示,会在项目根目录下生成_ide_helper.php,可以根据团队需要决定是否将该文件加入.gitignore
php artisan ide-helper:generate
为模型生成注释,要在创建完成模型文件和数据迁移文件运行之后,若数据库字段有注释,则模型字段也会有注释
#不加命令参数给所有模型生成注释
php artisan ide-helper:models
#包含指定模型
php artisan ide-helper:models "App\Models\ExcelDemo"
#忽略指定模型
php artisan ide-helper:models --ignore="App\Models\BaseModel"
#会提示是否覆盖原模型,不覆盖会在根目录下生成_ide_helper_models.php文件,推荐no选项
Do you want to overwrite the existing model files? Choose no to write to _ide_helper_models.php instead (yes/no) [no]:
>
使用 Travis-CI 做自动化测试
使用 StyleCI 自动修复代码格式
编辑器相关插件如下
IP查询工具集合
Linux文件系统 FAQ
rm cannot remove xxx Read-only file system 无法删除文件
df dir 查看无法删除的目录所在的文件系统
df /snap/remmina/
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/nvme0n1p2 479152840 195515620 259227828 43% /
fsck -y / #执行修复文件系统 的挂载根目录 或者 有问题的文件所在的挂载目录;
shutdown -r now
再删除ubuntu系统中的snap应用文件时上述方法没有解决
使用df -h 查看 发现remmina中的 /snap/remmina/4978 的挂载点是/dev/loop12
sudo umount /dev/loop12 去掉挂载后,再删除就可以了 ,原因是磁盘的挂载目录无法直接被删除
laravel广播使用笔记,基于laravel-websocket扩展包
阅读文档
安装需要的用的依赖
//websocket服务端
composer require beyondcode/laravel-websockets
//发布数据迁移文件
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"
//发布配置文件
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"
//安装队列管理面板 或者 使用php artisan queue:work也可以
composer require laravel/horizon
php artisan horizon:install
//执行迁移
php artisan migrate
//前端依赖
npm install laravel-echo pusher-js
修改配置
.env 配置
//广播驱动设置为pusher
BROADCAST_DRIVER=pusher
//队列驱动改为redis
QUEUE_CONNECTION=redis
//使用laravel-websockets做后端,pusher配置随便填写
PUSHER_APP_ID=yangliuan
PUSHER_APP_KEY=yangliuan
PUSHER_APP_SECRET=yangliuan
//注意一定要注释这行,否则laravel-websockets不生效
#PUSHER_APP_CLUSTER=mt1
//websocket端口号
LARAVEL_WEBSOCKETS_PORT=6001
config/app.php 配置
取消如下Provider的注释
/*
* Application Service Providers...
*/
...
// App\Providers\BroadcastServiceProvider::class,
config/broadcasting.php 配置
按如下修改
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
//本地开发关闭安全连接
'useTLS' => false,
//本地host配置
'host' => '127.0.0.1',
//端口
'port' => env('LARAVEL_WEBSOCKETS_PORT', 6001),
//协议
'scheme' => 'http',
],
],
config/websockets.php
'apps' => [
[
'id' => env('PUSHER_APP_ID'),
'name' => env('APP_NAME'),
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'path' => env('PUSHER_APP_PATH'),
'capacity' => null,
//是否开启客户端发送消息
'enable_client_messages' => false,
//是否开启统计
'enable_statistics' => true,
],
],
测试案例场景一
使用laravel excel 队列导出文件后,自动提示并下载,使用公共频道 demo地址
后端代码
注册频道
route/channels.php 文件,可以自定义频道名称
Broadcast::channel('excel', function () {
return true;
});
创建ExcelExportCompletedEvent事件
php artisan make:event ExcelExportCompletedEvent
<?php
use Illuminate\Broadcasting\Channel;//公共频道
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel; //存在频道可以加入和离开,需要授权
use Illuminate\Broadcasting\PrivateChannel; //私有频道,需要授权
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
//注意事件一定要实现ShouldBroadcast接口
class ExcelExportCompletedEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
//public属性会自动转换为广播数据
//自定义广播数据 文档 https://learnku.com/docs/laravel/9.x/broadcasting/12223#b2f5d1
public $excel_path;
public $disk;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(string $excel_path, string $disk)
{
//文件路径
$this->excel_path = $excel_path;
//磁盘
$this->disk = $disk;
}
/**
* 监听频道
* 监听自己的定义频道名称
*
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('excel');
}
}
创建导出文件 ExcelDemoPictureQueryExport 细节略过详情看 laravel excel文档
创建通知队列,用于触发时间
php artisan make:job ExcelNotifyJob
class ExcelNotifyJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $attach;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(array $attach)
{
$this->attach = $attach;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
//发送广播通知
ExcelExportCompletedEvent::dispatch($this->attach['file_name'], $this->attach['disk']);
}
}
控制器代码
/**
* 字段导出图片 使用队列 并接受广播通知
*
* @param Request $request
* @return void
*/
public function queueImages(Request $request)
{
$file_name = 'excel-demo-'.date('YmdHis').\mt_rand(100000, 999999).'.xlsx';
$disk = 'public';
Excel::queue(new ExcelDemoPictureQueryExport(), $file_name, $disk)
//导出成功后,使用任务链调用excel通知job
//DOC:https://learnku.com/docs/laravel/8.5/queues/10395#dispatching-jobs
//DOC:https://docs.laravel-excel.com/3.1/exports/queued.html#appending-jobs
->chain([
new ExcelNotifyJob(compact('file_name', 'disk'))
]);
return response()->json();
}
//下载文件方法
public function store(Request $request)
{
$request->validate([
'storage_path' => 'bail|required|string',
'disk' => 'bail|nullable|string',
]);
$realPath = Storage::disk($request->input('disk') ?? 'public')
->path($request->input('storage_path'));
return response()->download($realPath)->deleteFileAfterSend();
}
前端代码
使用 Laravel Jetstream Inertia.js 构建
封装laravel-echo.js
import Echo from 'laravel-echo';
window.pusher = require('pusher-js');
const echo = new Echo({
broadcaster: 'pusher',
key: 'yangliuan',
wsHost: window.location.hostname,
wsPort: 6001,
forceTLS: false,
enabledTransports: ['ws', 'wss'],
})
export { echo }
Excel.vue
<template>
<app-layout title="Dashboard">
...
<a href="#" @click="queueImagesClick">
<div class="mt-3 flex items-center text-sm font-semibold text-indigo-700">
<div>队列导出图片并用广播接受通知</div>
<div class="ml-1 text-indigo-500">
<svg viewBox="0 0 20 20" fill="currentColor" class="w-4 h-4"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</div>
</div>
</a>
</app-layout>
</template>
<script>
...
//导入laravel echo
import { echo } from '@/laravel-echo'
export default defineComponent({
components: {
AppLayout,
JetApplicationLogo,
Link
},
created() {
//监听公共频道excel,响应下载excel文件
echo.channel('excel')
.listen('ExcelExportCompletedEvent', (e) => {
alert('ExcelExportCompletedEvent')
this.downloadExcel(e.excel_path,e.disk)
console.log(e);
})
},
methods: {
//下载方法
downloadExcel(excel_path,disk) {
const download_url = '/api/files/download?storage_path=' + excel_path + '&disk=' + disk
window.open(download_url)
},
//点击时间调用队列导航图片接口
queueImagesClick() {
axios.post('/api/excel/export/queue-images').then( response => {
console.log(response)
})
}
}
})
</script>
//开启websocket服务
php artisan websockets:serve
//开启horizon队列
php artisan horizon
演示
授权频道案例
nginx代理websocket
websocket单独使用一个域名不和http接口共享域名,配置如下
server {
listen 80;
server_name websocket.exhibition.demo;
location / {
proxy_pass http://127.0.0.1:6001;
proxy_read_timeout 60;
proxy_connect_timeout 60;
proxy_redirect off;
# Allow the use of websockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
第二种方式websocket和http接口公用一个域名
map $http_upgrade $type {
default "";
websocket "ws";
}
server {
listen 80;
server_name api2.exhibition.demo;
root /home/yangliuan/Code/Php/business-logic/laravel-exhibition/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location = /favicon.ico {
access_log off; log_not_found off;
}
location = /robots.txt {
access_log off; log_not_found off;
}
//http
location / {
try_files $uri $uri/ /index.php?$query_string;
}
//websocket
location @ws {
proxy_pass http://127.0.0.1:6001;
proxy_set_header Host $host;
proxy_read_timeout 60;
proxy_connect_timeout 60;
proxy_redirect off;
# Allow the use of websockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location ~ [^/]\.php(/|$) {
fastcgi_pass unix:/dev/shm/php-cgi.sock;
fastcgi_index index.php;
include fastcgi.conf;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
参考
FAQ: mysqld_safe mysqld from pid file xxx.pid ended
处理一个兼职人员部署的服务器故障
1.php故障
Warning: require_once(ROOTPATHconfig/bluebee.inc.php): failed to open stream: No such file or directory in /web/code/mygym/mygym_pc/include/head.php on line 23
Fatal error: require_once(): Failed opening required 'ROOTPATHconfig/bluebee.inc.php' (include_path='.:/usr/local/php54/lib/php') in /web/code/mygym/mygym_pc/include/head.php on line 23
boss反馈,一个兼职人员开发部署的项目,出现了这个问题,根据经验初步判断,是文件不存在了,或者目录没有权限,登录之后发现,这个phper根本没有linux基础,以及不懂php-fpm运行机制,文件用户和组是 nginx 然后给了777权限
解决方法
service php-fpm status 显示 php-fpm 是www 用户跑的,但是当前服务器没有该用户
执行如下命令,创建www用户并加入www用户组
groupadd www
useradd -g www -M -s /sbin/nologin www
更改代码目录权限
//更改用户组
chown -R www.www /web/code
//更改目录权限
chmod -R 755 /web/code
文件权限根据情况可以给644
2.php报错提示mysql连接失败
service mysqld status 显示启动失败,查看/var/log/mysqld.log 日志 报错如下
mysqld_safe mysqld from pid file /var/lib/mysql/mysqld.pid ended
/etc/my.cnf配置如下
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.6/en/server-configuration-defaults.html
[mysqld]
skip-grant-tables
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
# Recommended in standard MySQL setup
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
发现是使用rpm包使用的社区版安装的。
尝试了各种发,都没有用,最后参考如下问答解决
restorecon -r /var/lib/mysql
service mysqld start
原因分析
可能是 /var/lib/mysql 目录,用户组 不是 mysql,
移动复制或修改文件时导致了 SELinux文件属性 丢失
首先保证 mysql 数据目录/var/lib/mysql 用户组 必须是 mysql
然后使用 restorecon 恢复文件的安全上下文
restorecon指令参考