
断路器 用作监控请求 是否合理 当出现异常流量 可以短路保护
具体使用方式通过切面编程 将需要监控的方法 包括controller service dao 的方法添加注解方式
然后当执行该方法时 会先进去hystrix定义的监控线程上
异步执行需监控的方法 并注册一个超时事件在 监控线程上
所以被HystrixCommand 注解的方法其实是异步执行的
思考 是否应该在网关应用上 添加hystrix 做断路器限流
的确是应该如此这样做
断路器 用作监控请求 是否合理 当出现异常流量 可以短路保护
具体使用方式通过切面编程 将需要监控的方法 包括controller service dao 的方法添加注解方式
然后当执行该方法时 会先进去hystrix定义的监控线程上
异步执行需监控的方法 并注册一个超时事件在 监控线程上
所以被HystrixCommand 注解的方法其实是异步执行的
思考 是否应该在网关应用上 添加hystrix 做断路器限流
的确是应该如此这样做
php 通过 symfony/http-foundation(http请求响应封装) 框架捕获http请求
laravel kernel 类 为laravel http 入口
middleware 类似于 过滤器 可以执行请求处理 然后next 执行处理链 必定有 handle 方法 当需要处理请求前操作 在调用 $next 前修改请求信息 当需要处理请求后 或者 在响应上操作 则 在$next后 修改信息 且返回结果必定为 $response对象
public function handle($request, Closure $next)
{
// Check if we're dealing with CORS and if we should handle it
if (! $this->shouldRun($request)) {
return $next($request);
}
// For Preflight, return the Preflight response
if ($this->cors->isPreflightRequest($request)) {
$response = $this->cors->handlePreflightRequest($request);
$this->cors->varyHeader($response, 'Access-Control-Request-Method');
return $response;
}
// Add the headers on the Request Handled event as fallback in case of exceptions
if (class_exists(RequestHandled::class) && $this->container->bound('events')) {
$this->container->make('events')->listen(RequestHandled::class, function (RequestHandled $event) {
$this->addHeaders($event->request, $event->response);
});
}
// Handle the request
$response = $next($request);
if ($request->getMethod() === 'OPTIONS') {
$this->cors->varyHeader($response, 'Access-Control-Request-Method');
}
return $this->addHeaders($request, $response);
}
nodejs 流对象操作 记录
自定义可写流
const {Writable} = require('stream')
class CounterStream extends Writable {
constructor(options){
super(options)
this.counter = 0
}
_write(chunk , encoding, callback){
console.log(chunk.toString("utf-8"))
this.counter+=chunk.length
callback.call()
}
}
module.exports = CounterStream
关键在于继承stream.Writeable 并且重写 _write(chunk , encoding, callback)
自定义可读流
const {Readable} = require('stream')
class MyReadableStream extends Readable {
constructor(options){
super(options)
this.isFinished = false
}
_read(size){
//待处理数据放在this._buffer中
if(!this.isFinished){
this.push("abc123")
this.isFinished = true
}else{
this.push(null)
}
}
}
module.exports = MyReadableStream
关键在于继承stream.Readable 并且重写 _read(size)
_read 方法中要把数据放到this.push的方法中 且 没有数据读取时 this.push(null) 结束读取
可以从Readable.pipe(Writable) 使用管道的方式 从可读流读取数据 pipe 到可写流中
注意 该方法为异步方法
特殊的流 socket 为双向流 可读可写
process.stdin 标准输入流
process.stdout 标准输出流
process.stderr 标准异常流
把标准输入流输出到标准输出流
const stdin = require('process').stdin
const stdout = require('process').stdout
const stderr = require('process').stderr
stdin.pipe(stdout)
执行后 主线程阻塞 读取标准输入流 读取到数据后 在 标准输出流输出
输入流事件有以下几个
输出流事件
Spring Cloud Netflix Sidecar框架提供了Sidecar模式的现成解决方案。Spring Cloud Netflix Sidecar框架框架可以提供对其他非Spring Cloud技术栈的微服务的治理。比如,你可以使用Node或者Golang php 编写一个Web项目,这个服务同样可以以Sidecar模式,纳入到Spring Cloud管理中去。
类似于数据管道处理的 框架 是一个面向数据的框架
可以兼容多种现有的消息处理框架 包括kafka MQ 等 也可以处理 java 特有JMS消息 RMI Socket 等数据接入点
核心信息用Message 代表
Channel 发送信息 send 拉取信息 receive 订阅消息 subscribe
queue channel 可以缓冲消息
channel interceptor 拦截器了 说明消息处理也是过滤链模式
channel.addInterceptor(Interceptor xxx)
xml 配置说明
spring-integration 可通过xml配置消息处理链 达到代码解耦效果
静态变量 : 在函数内部以static 作为声明前缀
全局变量 : 在函数内部以global作为声明前缀
共同点
静态变量与全局变量当同一方法在一次访问后更新后 能一直维持该值的该值 第二次 也依然能读取上次的赋值
最大的访问域是一个请求 不同请求下的值不一样。(php 一次请求就是一个进程 进程内部变量不能共享)
不同点
静态变量 在方法内部声明 也只能在方法内部使用
全局变量 在任何地方声明 在任何地方调用
且可以通过GLOBALS[‘xxx’]调用
$var = "world";
$helloWorld = "hello {$var}";
echo $helloWorld;
双引号自带模板语法功能 花括号自带变量替换功能
nginx 配置
root /var/www/php; // 新版本 root 要放在这里次啊能起作用
location ~\.php$ {
root /var/www/php;
index index.php index.htmlindex.htm;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
服务器 安装 php-fpm
然后 nginx 通过unix:/run/php/php7.4-fpm.sock 转发请求到php-fpm上
tips : fastcgi_params 添加以下配置(若访问首页空白)
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_script_name;
//从nginx变量 传到 cgi变量(即php变量)
fastcgi_param 参数详解 就是从nginx传过去的变量 可以通过_SERVER 获取
关键变量是
DOCUMENT_ROOT php 项目文件所在文件夹
SCRIPT_NAME php 项目文件
SCRIPT_FILENAME $document_root$fastcgi_script_name; //php 文件全路径
nginx变量 都是$开头小写下划线组合
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
以上参数可以通过 php $_SERVER[‘SERVER_NAME’] 获取变量值
php 实现多继承的组件
<?php
trait ezcReflectionReturnInfo {
function getReturnType() { /*1*/ }
function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
use ezcReflectionReturnInfo;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
use ezcReflectionReturnInfo;
/* ... */
}
?>
trait 定义组件
内部function定义方法接口 可以有实现的代码
在具体某个类 内部 通过关键字 use 引入trait 组件
当有相同名称方法trait 还优先调用 可通过parent:: 调用本来继承下来的方法
安装excel 包
composer require maatwebsite/excel
新增一个action操作
php artisan admin:action WeinpinhuiUser/ImportAction --name="导入"
<?php
namespace App\Admin\Actions\WeinpinhuiUser;
use App\Imports\WeipinhuiUser\ImportWeipinhuiUser;
use Encore\Admin\Actions\Action;
use Encore\Admin\Facades\Admin;
use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
class ImportAction extends Action
{
protected $selector = '.import-action';
public function handle(Request $request)
{
// $request ...
try{
// $request ...
$file = $request-> file('file');
Excel::import(new ImportWeipinhuiUser(),$file);
return $this->response()->success('数据导入成功')->refresh();
}catch (\Exception $e){
return $this->response()->error($e -> getMessage());
}
}
public function html()
{
return <<<HTML
<a class="btn btn-sm btn-default import-action">导入</a>
HTML;
}
public function form()
{
$this
->file('file', '请选择文件')
->options(['showPreview' => false,
'allowedFileExtensions'=>['xlsx','xls'],
'showUpload'=>false
]);
}
public function handleActionPromise()
{
$resolve = <<<SCRIPT
var actionResolverss = function (data) {
$('.modal-footer').show()
$('.tips').remove()
var response = data[0];
var target = data[1];
if (typeof response !== 'object') {
return $.admin.swal({type: 'error', title: 'Oops!'});
}
var then = function (then) {
if (then.action == 'refresh') {
$.admin.reload();
}
if (then.action == 'download') {
window.open(then.value, '_blank');
}
if (then.action == 'redirect') {
$.admin.redirect(then.value);
}
};
if (typeof response.html === 'string') {
target.html(response.html);
}
if (typeof response.swal === 'object') {
$.admin.swal(response.swal);
}
if (typeof response.toastr === 'object') {
$.admin.toastr[response.toastr.type](response.toastr.content, '', response.toastr.options);
}
if (response.then) {
then(response.then);
}
};
var actionCatcherss = function (request) {
$('.modal-footer').show()
$('.tips').remove()
if (request && typeof request.responseJSON === 'object') {
$.admin.toastr.error(request.responseJSON.message, '', {positionClass:"toast-bottom-center", timeOut: 10000}).css("width","500px")
}
};
SCRIPT;
Admin::script($resolve);
return <<<SCRIPT
$('.modal-footer').hide()
let html = `<div class='tips' style='color: blue;font-size: 15px;'>正在处理中<img src="data:image/gif;base64,R0lGODlhEAAQAPQAAP///1VVVfr6+np6eqysrFhYWG5ubuPj48TExGNjY6Ojo5iYmOzs7Lq6utjY2ISEhI6OjgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAAFUCAgjmRpnqUwFGwhKoRgqq2YFMaRGjWA8AbZiIBbjQQ8AmmFUJEQhQGJhaKOrCksgEla+KIkYvC6SJKQOISoNSYdeIk1ayA8ExTyeR3F749CACH5BAkKAAAALAAAAAAQABAAAAVoICCKR9KMaCoaxeCoqEAkRX3AwMHWxQIIjJSAZWgUEgzBwCBAEQpMwIDwY1FHgwJCtOW2UDWYIDyqNVVkUbYr6CK+o2eUMKgWrqKhj0FrEM8jQQALPFA3MAc8CQSAMA5ZBjgqDQmHIyEAIfkECQoAAAAsAAAAABAAEAAABWAgII4j85Ao2hRIKgrEUBQJLaSHMe8zgQo6Q8sxS7RIhILhBkgumCTZsXkACBC+0cwF2GoLLoFXREDcDlkAojBICRaFLDCOQtQKjmsQSubtDFU/NXcDBHwkaw1cKQ8MiyEAIfkECQoAAAAsAAAAABAAEAAABVIgII5kaZ6AIJQCMRTFQKiDQx4GrBfGa4uCnAEhQuRgPwCBtwK+kCNFgjh6QlFYgGO7baJ2CxIioSDpwqNggWCGDVVGphly3BkOpXDrKfNm/4AhACH5BAkKAAAALAAAAAAQABAAAAVgICCOZGmeqEAMRTEQwskYbV0Yx7kYSIzQhtgoBxCKBDQCIOcoLBimRiFhSABYU5gIgW01pLUBYkRItAYAqrlhYiwKjiWAcDMWY8QjsCf4DewiBzQ2N1AmKlgvgCiMjSQhACH5BAkKAAAALAAAAAAQABAAAAVfICCOZGmeqEgUxUAIpkA0AMKyxkEiSZEIsJqhYAg+boUFSTAkiBiNHks3sg1ILAfBiS10gyqCg0UaFBCkwy3RYKiIYMAC+RAxiQgYsJdAjw5DN2gILzEEZgVcKYuMJiEAOwAAAAAAAAAAAA=="><\/div>`
$('.modal-header').append(html)
process.then(actionResolverss).catch(actionCatcherss);
SCRIPT;
}
}
在列表工具按钮添加导入action
$grid->tools(function (Grid\Tools $tools) {
$tools->append(new ImportAction());
});
界面渲染已完成
现在处理数据保存
添加数据保存对象
php artisan make:import WeipinHuiUser/ImportWeipinhuiUser --model=App\Models\WeipinhuiUser
<?php
namespace App\Imports\Member;
use App\Models\MemberModel;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithStartRow;
class ImportWeinpinhuiUser implements ToModel,WithStartRow
{
/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
// 0代表的是第一列 以此类推
// $row 是每一行的数据
return new WeipinhuiUser([
'employee_no' => $row[0],
'name' => $row[1]
]);
}
/**
* 从第几行开始处理数据 就是不处理标题
* @return int
*/
public function startRow(): int
{
return 2;
}
}
注意:对应的model添加对应属性为可批量处理
class WeipinhuiUser extends Model
{
use HasFactory;
protected $fillable = ['employee_no', 'name'];
}