我的2016

时光匆匆流逝,转眼2016年即将过去了。今年对我来说比较特殊,因为我毕业了,正式从一个学生变成一个真正的打工仔了。下面想自己总结下我的2016年。

技术

  • 掌握了datatables,可以熟练的运用它,可以做出各种各样的表格
  • editor,可以自己扩展字段,可以编辑任意类型的form
  • 可以比较轻松的看懂别人的jquery插件源码,和自己定义些插件
  • node.js
  • mongodb,mongoose
  • vue以及它的全家桶【vue-route,vuex,vue-i18n等】【10月份后的重点基本都是它了】

生活

  • 去厦门旅游了一次【我的妈呀,怎么才去一个地方啊!还是毕业旅游呢!】
  • 接待了10几个好朋友,有的是当兵后几年没见的,有的是高中毕业后难得一见的,反正是朋友是兄弟我就乐意接待。
  • 还有比较郁闷的是家里好多人生病了,外公病了,外婆病了,姨妈病了,三伯病了。唉,也许我的成长就是家人的衰老,珍惜家人,珍惜和他们的每一分钟,过年多多陪陪家人 坚决不浪了
  • 总体生活还是比较平淡,但是觉得还不错,哈哈!也许这就叫平平淡淡才是真。

成绩

  • 给老师做了一个成绩管理系统【也没给反馈,比较我也是花了不多时间,估计不好用】
  • 做了一套可以自动吐代码的系统【吐出来了一套上线的代码,思想是欧克,又在完善了】
  • 其他不成体系的就算了【聊天室啊,一些小游戏,对那个双扣我还没搞完

思想

  • 听了比较多的喜马拉雅【明成祖朱棣,鬼谷子的局,逻辑思维,杜月笙,黄金荣,刘备,曹操,宋太祖,大国医,项羽等】,觉得每个人的成功都不是随随便便的,看似是机遇的东西起码都是建立在能力的基础上。觉得还是得时刻武装自己,好让机会来临的时候可以有所作为。因为历史给了我太多假如了,假如鸿门宴杀了刘邦,假如刘备不那么一时冲动,假如曹操把司马懿给做了。但这些都是假如,历史就是历史,没有假如,历史给我的就是借鉴。【那天看了李叫兽的一种学习方法,他说古代帝王看历史都是看到做出决策的时候将书合上,然后自己先思考,再看历史是如何演绎】
  • 觉得自己还是得多看书,多写东西,多发布源码

2017的目标

  • 学会系统的整理自己的知识点,将简书好好的用起来
  • 多在github上面发布些自己已做的源码
  • 还是得不断的学习,毕竟自己还是太嫩了

go go go

网站压力测试-工具篇

webbench

最多可以模拟3万个并发连接去测试网站的负载能力,个人感觉要比Apache自带的ab压力测试工具好,安装使用也特别方便。

webbench 的安装

wget http://home.tiscali.cz/cz210552/distfiles/webbench-1.5.tar.gz
tar zxvf webbench-1.5.tar.gz
cd webbench-1.5
make && make install

Ubuntu 下安装使用

1. 安装依赖包CTAGS
apt-get install ctags
2. 安装 Webbench
下载程序: [webbench-1.5.tar.gz](http://home.tiscali.cz/~cz210552/distfiles/webbench-1.5.tar.gz)
wget http://home.tiscali.cz/~cz210552/distfiles/webbench-1.5.tar.gz make sudo make install

webbench 查看命令帮助

webbench -?

webbench 使用方法

webbench -c 500 -t 30 [http://127.0.0.1/test.php](http://127.0.0.1/test.php)

webbench 的参数说明 -c 表示并发数(客户端数),-t 表示时间(秒)

webbench 测试结果

Webbench – Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://127.0.0.1/phpionfo.php
500 clients, running 30 sec.

Speed=3230 pages/min, 11614212 bytes/sec.
Requests: 1615 susceed, 0 failed.

分析:每秒钟响应请求数:3230 pages/min,每秒钟传输数据量11614212 bytes/sec.

ab

Apache附带的压力测试工具ab,非常容易使用,并且完全可以摸你各种条件对Web服务器发起测试请求。ab可以直接在Web服务器本地发起测试请求,这对于需要了解服务器的处理性能至关重要,因为它不包括数据的网络传输时间以及用户PC本地的计算时间。

要执行 1000 次的 connection, 20 次的 concurrent (并行, 同时):

语法: ab -n 1000 -c 20 www.baidu.com, -n 请求数, -c 并发数

产生出来的结果. 要注意的是以下几个:

§ Time taken for tests: 总共执行花了多久的时间.(以上 1000 次共多久)
§ Requests per second: 每秒平均可以处理多少个 connection.

参数详解

-n 测试会话中所执行的请求个数,默认仅执行一个请求
-c 一次产生的请求个数,即同一时间发出多少个请求,默认为一次一个
-t 测试所进行的最大秒数,默认为无时间限制....其内部隐含值是[-n 50000],它可以使对服务器的测试限制在一个固定的总时间以内
-p 包含了需要POST的数据的文件
-T POST数据所使用的Content-type头信息
-v 设置显示信息的详细程度
-w 以HTML表格的形式输出结果,默认是白色背景的两列宽度的一张表
-i 以HTML表格的形式输出结果,默认是白色背景的两列宽度的一张表
-x 设置<table>属性的字符串,此属性被填入<table 这里>
-y 设置<tr>属性的字符串
-z 设置<td>属性的字符串
-C 对请求附加一个Cookie行,其典型形式是name=value的参数对,此参数可以重复
-H 对请求附加额外的头信息,此参数的典型形式是一个有效的头信息行,其中包含了以冒号分隔的字段和值的对(如"Accept-Encoding: zip/zop;8bit")
-A HTTP验证,用冒号:分隔传递用户名及密码
-P 无论服务器是否需要(即是否发送了401认证需求代码),此字符串都会被发送
-X 对请求使用代理服务器
-V 显示版本号并退出
-k 启用HTTP KeepAlive功能,即在一个HTTP会话中执行多个请求,默认为不启用KeepAlive功能
-d 不显示"percentage served within XX [ms] table"的消息(为以前的版本提供支持)
-S 不显示中值和标准背离值,且均值和中值为标准背离值的1到2倍时,也不显示警告或出错信息,默认会显示最小值/均值/最大值等(为以前的版本提供支持)
-g 把所有测试结果写入一个'gnuplot'或者TSV(以Tab分隔的)文件
-e 产生一个以逗号分隔的(CSV)文件,其中包含了处理每个相应百分比的请求所需要(从1%到100%)的相应百分比的(以微妙为单位)时间
-h 显示使用方法
-k 发送keep-alive指令到服务器端

(jwt+dingo)和(passport+dingo)使用

参考资料

 [Laravel实现dingo+JWT api接口之配置篇](http://blog.csdn.net/qq_28666081/article/details/52187612)
[Laravel实现dingo+JWT api接口之实战篇](http://blog.csdn.net/qq_28666081/article/details/52188549)

安装dingo

  • 你需要修改你的 composer.json 文件,然后执行 composer update 把最后一个版本的包加入你的项目
"require": {
    "dingo/api": "1.0.*@dev"
}

或者直接

composer require dingo/api:1.0.x@dev
  • 打开 config/app.php,注册必要的 service provider 在你的应用 providers 之前。
'providers' => [
    Dingo\Api\Provider\LaravelServiceProvider::class,
]
  • 生成dingo配置文件 config/api.php :
php artisan vendor:publish --provider="Dingo\Api\Provider\LaravelServiceProvider"
  • .env添加基础配置(四个即可, 其他为额外提供):
#标准树
API_STANDARDS_TREE=vnd
#前缀
API_PREFIX=api
#版本
API_VERSION=v1
#开启调试
API_DEBUG=true
phpAPI_STANDARDS_TREE=vnd
API_SUBTYPE=biubiujun
API_PREFIX=api
API_VERSION=v1
API_NAME=BiuBiuJun
API_CONDITIONAL_REQUEST=false
API_STRICT=false
API_DEFAULT_FORMAT=json
API_DEBUG=true
API_STANDARDS_TREE - API规格 
# 未注册的树(x)主要表示本地和私有环境
#私有树(prs)主要表示没有商业发布的项目
# 供应商树(vnd)主要表示公开发布的项目 是一种概念上的东西,类似与git的分支,如果正常开发就按照 x,prs,vnd 的描述来填写即可。
  1 本地或私有环境 
  2 prs 非商业销售的项目 
  3 vnd 公开的以及商业销售的项目
API_SUBTYPE - API简称, 在请求header中需要用到它
API_PREFIX - API前缀(或使用API_DOMAIN - API子域名), 如果不需要请填写 '/'
API_VERSION - API默认版本
API_NAME - API名称,用于生成api文档,其他地方不使用
API_CONDITIONAL_REQUEST - 带条件的请求,由于缓存API请求的时候会使用客户端缓存功能,所以默认开启了带条件的请求 
API_STRICT - 严格模式,要求客户端发送Accept头而不是默认在配置文件中指定的版本 
API_DEFAULT_FORMAT - 响应格式,默认的响应格式是JSON 
API_DEBUG - 调试模式

# API规格 ①x 本地或私有环境 ②prs非商业销售的项目 ③vnd 公开的以及商业销售的项目
API_STANDARDS_TREE=vnd
# API_SUBTYPE - API简称
API_SUBTYPE=ssapi
# API前缀(或使用API_DOMAIN - API子域名) 
API_PREFIX=api
# API 默认版本    
API_VERSION=v1
# API名称      
API_NAME=ssapi
# 带条件的请求,由于缓存API请求的时候会使用客户端缓存功能,所以默认开启了带条件的请求   
API_CONDITIONAL_REQUEST=false
# 严格模式,要求客户端发送Accept头而不是默认在配置文件中指定的版本 
解释一下:因为我们不在 URI 中指定具体的版本,所以我们需要定义 Accept 头去请求具体的版本。头信息格式如下。 
Accept: application/vnd.YOUR_SUBTYPE.v1+json 
API_STRICT=false
# 响应格式,返回的类型,默认的响应格式是JSON
API_DEFAULT_FORMAT=json
# 调试模式
API_DEBUG=true

安装jwt

  • 你需要修改你的 composer.json 文件,然后执行 composer update 把最后一个版本的包加入你的项目
"require": {
    "tymon/jwt-auth": "0.5.*",
}

或者直接

composer require tymon/jwt-auth
  • 打开 config/app.php,注册到 providers 数组。
'providers'=>[
  Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
]
  • 注册jwt门面:
'aliases'=>[
  'JWTAuth'=> Tymon\JWTAuth\Facades\JWTAuth::class,
  'JWTFactory'=> Tymon\JWTAuth\Facades\JWTFactory::class,
]
  • 生成jwt配置文件 config/jwt.php :
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"
  • 生成 jwt.php 文件中数组的 secret 键成对应的值:
php artisan jwt:generate

关联dingo与JWT

修改 config/api.phpauth 如下:

'auth' => [  
    'basic' => function($app){  
        return new Dingo\Api\Auth\Provider\Basic($app['auth']);  
    },  
    'jwt' => function($app){  
        return new Dingo\Api\Auth\Provider\JWT($app['Tymon\JWTAuth\JWTAuth']);  
    }  
],  

安装passport

  • 使用 Composer 依赖包管理器安装 Passport :
composer require laravel/passport
  • 接下来,将 Passport 的服务提供者注册到配置文件 config/app.phpproviders 数组中:
Laravel\Passport\PassportServiceProvider::class,

Passport 使用服务提供者注册内部的数据库迁移脚本目录,所以上一步完成后,你需要更新你的数据库结构。Passport 的迁移脚本会自动创建应用程序需要的客户端数据表和令牌数据表:

执行 php artisan migrate, 添加了如下几张表:

Migrating: 2016_06_01_000001_create_oauth_auth_codes_table
Migrating: 2016_06_01_000002_create_oauth_access_tokens_table
Migrating: 2016_06_01_000003_create_oauth_refresh_tokens_table
Migrating: 2016_06_01_000004_create_oauth_clients_table
Migrating: 2016_06_01_000005_create_oauth_personal_access_clients_table

如果你不打算使用 Passport 的默认迁移,你应该在 AppServiceProviderregister 方法中调用 Passport :: ignoreMigrations 方法。 你可以导出这个默认迁移用 php artisan vendor:publish --tag=passport-migrations 命令。

  • 接下来,你需要运行 passport:install 命令来创建生成安全访问令牌时用到的加密密钥,同时,这条命令也会创建「私人访问」客户端「密码授权」客户端:【运行 passport:install 命令,该命令将会创建生成安全访问令牌(token)所需的加密键,此外,该命令还会创建 personal accesspassword grant 客户端用于生成访问令牌,该命令会在 storage 目录中生成认证需要的加密键, oauth-private.keyoauth-public.key
php artisan passport:install

执行上述代码后的结果:

Encryption keys generated successfully.
Personal access client created successfully.
Client ID: 1
Client Secret: e7pPOyPMFiEuE5EvtDvY9qsesfTgqNhb61r37cez
Password grant client created successfully.
Client ID: 2
Client Secret: eI4XKieiDQRUCMpnfb3g5MOr8SItQ5rCZBv3bWO3
  • 上面命令执行后,请将 Laravel\Passport\HasApiTokens Trait 添加到 App\User 模型中,这个 Trait 会给你的模型提供一些辅助函数,用于检查已认证用户的令牌和使用作用域:
<?php
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}
  • 接下来,需要在 AuthServiceProviderboot 方法中调用 Passport::routes 函数。这个函数会注册一些在访问令牌、客户端、私人访问令牌的发放和吊销过程中会用到的必要路由:
<?php
namespace App\Providers;
use Carbon\Carbon;
use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();

        Passport::tokensExpireIn(Carbon::now()->addDays(15));

        Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));

        Passport::pruneRevokedTokens();
    }
}

最后,需要将配置文件 config/auth.phpapi 部分的授权保护项( driver )改为 passport 。此调整会让你的应用程序在接收到 API 的授权请求时使用 Passport 的 TokenGuard 来处理:

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'passport',
        'provider' => 'users',//【可能这里需要修改】
    ],
],
  • 如果用手机号进行授权的话,需要修改模型
    /**
     * [findForPassport passport通过手机号/账号验证]
     * @param  [type] $username [description]
     * @return [type]           [description]
     */
    public function findForPassport($username)
    {
        // if (!$this->where('phone', $username)->first()) {
        //     return $this->where('name', $username)->first();
        // }
        // return true;

        return $this->where('phone', $username)->first();

        // return $this->where('phone', $username)->first() || $this->where('name', $username)->first();
    }

dingo+passport结合

  • 创建一个密码发放客户端
php artisan passport:client --password

配置Dingo使用Passport密码发放令牌

  • 创建 PassportDingoProvider
php artisan make:provider PassportDingoProvider
  • 修改 app/Providers/PassportDingoProvider.php
<?php
namespace App\Providers;
use Dingo\Api\Routing\Route;
use Illuminate\Http\Request;
use Dingo\Api\Auth\Provider\Authorization;
class PassportDingoProvider extends Authorization
{
    public function authenticate(Request $request, Route $route)
    {
        return $request->user();
    }
    public function getAuthorizationMethod()
    {
        return 'bearer';
    }
}
  • 修改 config/api.php
'auth' => [ 
    'custom' => \App\Providers\PassportDingoProvider::class
],
  • 修改 App/Http/Kernel.php
protected $middlewareGroups = [
   ...
   'api:auth' => [
       'auth:api',
       'api.auth'
    ]
    ...
];
  • routes/api.php 修改之前注册路由
$api = app('Dingo\Api\Routing\Router');
$api->version('v1', ['middleware' => 'api:auth', 'namespace' => 'App\Http\Controllers\Api\V1'], function ($api) {
    $api->get('user/{id}', 'UserController@show');
    $api->get('user', 'UserController@index');
});
  • 测试-请求令牌

curl -d "username=biubiujun@163.com@password=123456@grant_type=password&client_id=<client_id>&client_secret=<client_secret>" http://localhost/path/public/api/oauth/token

  • 测试-请求用户列表
curl -H "Authorization: Bearer <token>" http://localhost/path/public/api/user

Swagger【api文档】

  • 安装
composer require zircote/swagger-php
  • 创建 SwaggerController
php artisan make:controller SwaggerController
  • 修改 app/Http/Controller/SwaggerController
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
class SwaggerController extends Controller
{
    public function doc()
    {
        $swagger = \Swagger\scan(__DIR__ . '/../');
        return response()->json($swagger);
    }
}
  • 下载 swagger-ui, swagger-ui 
  • 将swagger-ui/dist目录放入public/doc
  • 修改public/doc/index.html
<script src='lang/translator.js' type='text/javascript'></script>
<script src='lang/zh-cn.js' type='text/javascript'></script>
<script type="text/javascript">
    $(function () {
      var url = window.location.search.match(/url=([^&]+)/);
        if (url && url.length > 1) {
          url = decodeURIComponent(url[1]);
        } else {
          // url = "http://petstore.swagger.io/v2/swagger.json"
          url = "/api/doc";
        }

访问http://localhost/path/public/doc/

Laravel 的自定义函数 helpers.php 文件存放位置

Laravel 的自定义函数 helpers.php 文件存放位置

  • 创建文件 app/helpers.php
if (!function_exists('make_sms_code')) {
    /**
     * [makeCode 随机字符串]
     * @param  integer $length [随机数长度]
     * @return [type]          [返回一个指定长度的字符串]
     */
    function make_sms_code($length = 5)
    {
        // 密码字符集,可任意添加你需要的字符
        $chars = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
        // 在 $chars 中随机取 $length 个数组元素键名
        $keys = array_rand($chars, $length);
        $code = '';
        for ($i = 0; $i < $length; $i++) {
            // 将 $length 个数组元素连接成字符串
            $code .= $chars[$keys[$i]];
        }
        return $code;
    }
}
  • 修改项目 composer.json

在项目 composer.jsonautoload 部分里的 files 字段加入该文件即可:

    "autoload": {
        "classmap": [
            "database/seeds",
            "database/factories"
        ],
        "psr-4": {
            "App\\": "app/"
        },
        "files": [
            "app/helpers.php"
        ]
    },
  • 然后运行:
composer dump-autoload