默凡

默凡 查看完整档案

北京编辑  |  填写毕业院校今日头条  |  前端研发 编辑 github.com/Mmzer 编辑
编辑

知行合一,天道酬勤

个人动态

默凡 发布了文章 · 2020-12-07

用 vscode调试nodejs 时,提示对应的 grpc 模块找不到

报错提示如下:

ERROR 2020-12-07 15:31:14,835 v1(6) [gulu-core]::UncaughtException 10.79.185.0 - - default - Error: Failed to load gRPC binary module because it was not installed for the current system
Expected directory: node-v67-darwin-x64-unknown
Found: [node-v83-darwin-x64-unknown]
This problem can often be fixed by running "npm rebuild" on the current system
Original error: Cannot find module '/Users/chenwei/repos/kunpeng/node_modules/grpc/src/node/extension_binary/node-v67-darwin-x64-unknown/grpc_node.node'
    at Object.<anonymous> (/Users/chenwei/repos/kunpeng/node_modules/grpc/src/grpc_extension.js:53:17)
    at Module._compile (internal/modules/cjs/loader.js:738:30)
    at Module._extensions..js (internal/modules/cjs/loader.js:749:10)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/chenwei/repos/kunpeng/node_modules/ts-node/src/index.ts:851:44)
    at Module.load (internal/modules/cjs/loader.js:630:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:570:12)
    at Function.Module._load (internal/modules/cjs/loader.js:562:3)
    at Module.require (internal/modules/cjs/loader.js:667:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (/Users/chenwei/repos/kunpeng/node_modules/grpc/src/client_interceptors.js:144:12)
Waiting for the debugger to disconnect...

调试了一下grpc模块,发现是调试模式下,node运行时的版本不对:
image.png

运行时的node版本是 11.10.1 版本,对应的 modules 版本是 67,所以当前版本下,和grpc版本对应的模块就是:node-v67-darwin-x64-unknown。
但我本地实际的版本是 14.13.0 版本,对应的 grpc 模块是 node-v83-darwin-x64-unknown,所以报错找不到:
image.png

究其原因,是vscode本身是一个js应用,使用的 electron 框架开发的桌面应用,里边内置的nodejs版本当前是 11.10.1 版本,且无法被改变:
image.png

解决办法,是在vscode的调试配置 .vscode/launch.json 文件里,用配置项runtimeVersion配置指定的node版:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "runtimeVersion": "14.13.0",
            "request": "launch",
            "name": "native_server",
            "console": "integratedTerminal",
            "cwd": "${workspaceFolder}/projects/native_server",
            "runtimeArgs": ["-r", "ts-node/register/transpile-only"],
            "args": ["./server/bootstrap.ts"]
        }
    ]
}

参考讨论issue:

查看原文

赞 1 收藏 1 评论 0

默凡 收藏了文章 · 2020-04-19

OS X 开发环境配置:homebrew + yarn + nvm

问题

brew install yarn --without-node 不再起作用,yarn 已经删除了 option --without-node

准备

homebrew 已安装。
(非必需条件)使用 zsh 替换 bash:

chsh -s /bin/zsh

安装步骤

  1. 安装 nvm:

    1. 确定 ~/.bash_profile 是否存在,如果没有则新建一个;执行 touch ~/.bash_profile
    2. 执行安装命令:

      // cURL:
      curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
      // or Wget:
      wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
    3. 安装 node:

      // 安装最新 node
      nvm install node --latest-npm
      // Always default to the latest available node version on a shell
      nvm alias default node
      1. 检查 node:

        node -v

        显示 node 版本,例如 v12.1.0

  2. 安装 yarn:

    1. 安装 yarn 时不安装 node:

      brew install yarn --ignore-dependencies
    2. 查找 node:

      which node

      显示 node 的安装位置,例如:/Users/<your's-user-name>/.nvm/versions/node/v12.1.0/bin/node

    3. 执行 brew doctor 检查依赖,会出现:

      Warning: Some installed formulae are missing dependencies.
      You should `brew install` the missing dependencies:
          brew install node
      
      Run `brew missing` for more details.
    4. 为 homebrew 创建 node 的 symbol link:

      ln -s ~/.nvm/versions/ /usr/local/Cellar/node
    5. 再次执行 brew doctor 进行检查,Warning 信息消失。

==================================================
brew 之后可能会删掉 --ignore-dependencies,最好还是使用其他方法安装 yarn,

curl -o- -L https://yarnpkg.com/install.sh | bash
查看原文

默凡 赞了文章 · 2020-04-19

OS X 开发环境配置:homebrew + yarn + nvm

问题

brew install yarn --without-node 不再起作用,yarn 已经删除了 option --without-node

准备

homebrew 已安装。
(非必需条件)使用 zsh 替换 bash:

chsh -s /bin/zsh

安装步骤

  1. 安装 nvm:

    1. 确定 ~/.bash_profile 是否存在,如果没有则新建一个;执行 touch ~/.bash_profile
    2. 执行安装命令:

      // cURL:
      curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
      // or Wget:
      wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
    3. 安装 node:

      // 安装最新 node
      nvm install node --latest-npm
      // Always default to the latest available node version on a shell
      nvm alias default node
      1. 检查 node:

        node -v

        显示 node 版本,例如 v12.1.0

  2. 安装 yarn:

    1. 安装 yarn 时不安装 node:

      brew install yarn --ignore-dependencies
    2. 查找 node:

      which node

      显示 node 的安装位置,例如:/Users/<your's-user-name>/.nvm/versions/node/v12.1.0/bin/node

    3. 执行 brew doctor 检查依赖,会出现:

      Warning: Some installed formulae are missing dependencies.
      You should `brew install` the missing dependencies:
          brew install node
      
      Run `brew missing` for more details.
    4. 为 homebrew 创建 node 的 symbol link:

      ln -s ~/.nvm/versions/ /usr/local/Cellar/node
    5. 再次执行 brew doctor 进行检查,Warning 信息消失。

==================================================
brew 之后可能会删掉 --ignore-dependencies,最好还是使用其他方法安装 yarn,

curl -o- -L https://yarnpkg.com/install.sh | bash
查看原文

赞 5 收藏 4 评论 1

默凡 赞了文章 · 2018-10-09

前端每日实战 2018 年 9 月份项目汇总(共 26 个项目)

过往项目

2018 年 8 月份项目汇总(共 29 个项目)

2018 年 7 月份项目汇总(共 29 个项目)

2018 年 6 月份项目汇总(共 27 个项目)

2018 年 5 月份项目汇总(共 30 个项目)

2018 年 4 月份项目汇总(共 8 个项目)

2018 年 9 月份发布的项目

《前端每日实战》专栏每天分解一个前端项目,用视频记录编码过程,再配合详细的代码解读,是学习前端开发的活的参考书!

124# 视频演示如何用纯 CSS 创作一只纸鹤

125# 视频演示如何用纯 CSS 创作一个失落的人独自行走的动画

126# 视频演示如何用纯 CSS 创作小球变矩形背景的按钮悬停效果

127# 视频演示如何用纯 CSS 创作一个圆环旋转错觉动画

128# 视频演示如何用纯 CSS 创作一个“女神来了,快让路”的动画

129# 视频演示如何用纯 CSS 创作一个条纹错觉动画

130# 视频演示如何用 CSS 在线字体和 D3 创作一个 Google & googol 信息图

131# 视频演示如何用纯 CSS 创作一把剪刀

132# 视频演示如何用纯 CSS 创作一只思考的手

133# 视频演示如何用 CSS 和 GSAP 创作有多个关键帧的连续动画

134# 视频演示如何用 CSS 和 GSAP 创作一个树枝发芽的 loader

135# 视频演示如何用纯 CSS 创作一个悬停时右移的按钮特效

136# 视频演示如何用 D3 和 GSAP 创作一个横条 loader

137# 视频演示如何用纯 CSS 创作一个抽象的水波荡漾的动画

138# 视频演示如何用纯 CSS 创作一张 iPhone 价格信息图

139# 视频演示如何用 CSS 和 D3 创作光斑粒子交相辉映的动画

140# 视频演示如何用纯 CSS 创作文本的淡入动画效果

141# 视频演示如何用 CSS 的 Grid 布局创作一枚小狗邮票

142# 视频演示如何用 CSS 的 Grid 布局创作一枚小鸡邮票

143# 视频演示如何用 CSS 的 Grid 布局创作一枚小松鼠邮票

144# 视频演示如何用 D3 和 GSAP 创作一个集体舞动画

145# 视频演示如何用纯 CSS 创作一个电源开关控件

146# 视频演示如何用纯 CSS 创作一个脉动 loader

147# 视频演示如何用纯 CSS 创作透视按钮的悬停特效

148# 视频演示如何用纯 CSS 创作从按钮两侧滑入装饰元素的悬停特效

149# 视频演示如何用纯 CSS 创作一个宝路薄荷糖的动画

查看原文

赞 64 收藏 37 评论 0

默凡 评论了文章 · 2018-09-12

前端nginx使用札记

nginx是什么?

nginx是俄罗斯人 Igor Sysoev为俄罗斯访问量第二的Rambler.ru站点开发的一个十分轻量级的HTTP服务器。它是一个高性能的HTTP和反向代理服务器,同时也可以作为IMAP/POP3/SMTP的代理服务器。nginx使用的是BSD许可。

Nginx 以事件驱动的方式编写,所以有非常好的性能,同时也是一个非常高效的反向代理、负载平衡。

Nginx 因为它的稳定性、丰富的模块库、灵活的配置和低系统资源的消耗而闻名。

nginx适合用来做mongrel clusters 的前端 HTTP 响应。

为什么要用nginx,nginx有什么特点?

nginx的特点

  • 核心特点:高并发请求的同时保持高效的服务
  • 热部署
  • 低内存消耗
  • 处理响应请求很快
  • 具有很高的可靠性

同时,nginx也可以实现高效的反向代理、负载均衡。

前端可以用nginx做些什么?

  • 搭建静态资源服务器
  • 反向代理分发后端服务(可以和nodejs搭配实现前后端分离)和跨域问题
  • 根据User Agent来重定向站点
  • 开发环境或测试环境切换(切换host)
  • url重写,使用rewrie规则本地映射
  • 资源内容篡改
  • 获取cookie做分流
  • 资源合并
  • gzip压缩
  • 压缩图片
  • sourceMap调试

如何安装nginx?

mac安装:

安装brew之后,执行命令:

$ sudo brew install nginx

windows安装

1.下载: nginx官网

  1. 解压运行:解压至c:\nginx,运行nginx.exe(即nginx -c conf\nginx.conf),默认使用80端口,日志见文件夹C:\nginx\logs
  2. 关闭:nginx -s stoptaskkill /F /IM nginx.exe > nul

【注意】以下皆以mac为例。

nginx如何启动、重启、关闭?

查看nginx版本:nginx -v

启动nginx服务:
方法一:运行命令:sudo brew services start nginx
方法二:运行命令:nginx
访问http://localhost:8080
出现如下界面则表示安装成功:
image

关闭nginx服务:
方法一:运行命令: sudo brew services stop nginx
方法二:运行命令: nginx -s stop
方法三:
运行命令:ps -ef | grep nginx,找到master对应的进程号。
快速停止:kill -TERM nginx进程号kill -INT nginx进程号
从容停止: kill -QUIT nginx进程号
强制停止所有nginx进程:pkill -9 nginx

重启nginx服务:
方法一:nginx -s reload
方法二: 平滑重启命令: kill -HUP nginx进程号

nginx信号控制:

  • TERM,INT 快速关闭
  • QUIT 从容关闭
  • HUP 平滑重启,重新加载配置文件
  • USR1 重新打开日志文件,在切割日志时用途较大
  • USR2 平滑升级可执行程序
  • WINCH 从容关闭工作进程

如何查看nginx的配置文件nginx.conf的路径和安装路径?

查看配置文件位置和测试配置文件语法:运行命令nginx -t:
image
查看nginx安装路径:
因为是使用brew安装的,所以使用brew命令:brew info nginx:
image

nginx.conf基本配置有哪些?

nginx配置文件主要分成四个部分:

  • main,全局设置,影响其它部分所有设置
  • server,主机服务相关设置,主要用于指定虚拟主机域名、IP和端口
  • location,URL匹配特定位置后的设置,反向代理、内容篡改相关设置
  • upstream,上游服务器设置,负载均衡相关配置

他们之间的关系式:server继承main,location继承server;upstream既不会继承指令也不会被继承。

如下是一份通用的配置和详解:

#定义 Nginx 运行的用户和用户组,默认由 nobody 账号运行, windows 下面可以注释掉。 
user  nobody; 

#nginx进程数,建议设置为等于CPU总核心数。可以和worker_cpu_affinity配合
worker_processes  1; 

#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#进程文件,window下可以注释掉
#pid        logs/nginx.pid;

# 一个nginx进程打开的最多文件描述符(句柄)数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,
# 但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致。
worker_rlimit_nofile 65535;

#工作模式与连接数上限
events {
    # 参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; 
    # epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
   #use epoll;
   #connections 20000;  # 每个进程允许的最多连接数
   # 单个进程最大连接数(最大连接数=连接数*进程数)该值受系统进程最大打开文件数限制,需要使用命令ulimit -n 查看当前设置
   worker_connections 65535;
}

#设定http服务器
http {
    #文件扩展名与文件类型映射表
    #include 是个主模块指令,可以将配置文件拆分并引用,可以减少主配置文件的复杂度
    include       mime.types;
    #默认文件类型
    default_type  application/octet-stream;
    #charset utf-8; #默认编码

    #定义虚拟主机日志的格式
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
    
    #定义虚拟主机访问日志
    #access_log  logs/access.log  main;

    #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
    sendfile        on;
    #autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。

    #防止网络阻塞
    #tcp_nopush     on;

    #长连接超时时间,单位是秒,默认为0
    keepalive_timeout  65;

    # gzip压缩功能设置
    gzip on; #开启gzip压缩输出
    gzip_min_length 1k; #最小压缩文件大小
    gzip_buffers    4 16k; #压缩缓冲区
    gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
    gzip_comp_level 6; #压缩等级
    #压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
    gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
    gzip_vary on; //和http头有关系,加个vary头,给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩,所以根据客户端的HTTP头来判断,是否需要压缩
    #limit_zone crawler $binary_remote_addr 10m; #开启限制IP连接数的时候需要使用

    # http_proxy服务全局设置
    client_max_body_size   10m;
    client_body_buffer_size   128k;
    proxy_connect_timeout   75;
    proxy_send_timeout   75;
    proxy_read_timeout   75;
    proxy_buffer_size   4k;
    proxy_buffers   4 32k;
    proxy_busy_buffers_size   64k;
    proxy_temp_file_write_size  64k;
    proxy_temp_path   /usr/local/nginx/proxy_temp 1 2;

   # 设定负载均衡后台服务器列表 
    upstream  backend.com  { 
        #ip_hash; # 指定支持的调度算法
        # upstream 的负载均衡,weight 是权重,可以根据机器配置定义权重。weigth 参数表示权值,权值越高被分配到的几率越大。
        server   192.168.10.100:8080 max_fails=2 fail_timeout=30s ;  
        server   192.168.10.101:8080 max_fails=2 fail_timeout=30s ;  
    }

    #虚拟主机的配置
    server {
        #监听端口
        listen       80;
        #域名可以有多个,用空格隔开
        server_name  localhost fontend.com;
        # Server Side Include,通常称为服务器端嵌入
        #ssi on;
        #默认编码
        #charset utf-8;
        #定义本虚拟主机的访问日志
        #access_log  logs/host.access.log  main;
        
        # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
        location / {
            root   html;
            index  index.html index.htm;
        }
        
        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

       # 图片缓存时间设置
       location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ {
          expires 10d;
       }

       # JS和CSS缓存时间设置
       location ~ .*.(js|css)?$ {
          expires 1h;
       }

        #代理配置
        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #location /proxy/ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }

    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
}

location如何匹配?

示例:

location  = / {
  # 精确匹配 / ,主机名后面不能带任何字符串
  [ configuration A ] 
}

location  / {
  # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
  # 但是正则和最长字符串会优先匹配
  [ configuration B ] 
}

location /documents/ {
  # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
  # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
  [ configuration C ] 
}

location ~ /documents/Abc {
  # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
  # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
  [ configuration CC ] 
}

location ^~ /images/ {
  # 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
  [ configuration D ] 
}

location ~* \.(gif|jpg|jpeg)$ {
  # 匹配所有以 gif,jpg或jpeg 结尾的请求
  # 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则
  [ configuration E ] 
}

location /images/ {
  # 字符匹配到 /images/,继续往下,会发现 ^~ 存在
  [ configuration F ] 
}

location /images/abc {
  # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在
  # F与G的放置顺序是没有关系的
  [ configuration G ] 
}

location ~ /images/abc/ {
  # 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用
    [ configuration H ] 
}

location ~* /js/.*/\.js
  • =开头表示精确匹配
  • ^~ 开头表示uri以某个常规字符串开头,不是正则匹配
  • ~ 开头表示区分大小写的正则匹配;
  • ~* 开头表示不区分大小写的正则匹配
  • / 通用匹配, 如果没有其它匹配,任何请求都会匹配到

优先级:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (/)

如何配置反向代理?

详解:

# 对 “/” 启用反向代理
location / {
  proxy_pass http://127.0.0.1:3000;  # 设置要代理的 uri,注意最后的 /。可以是 Unix 域套接字路径,也可以是正则表达式。
  proxy_redirect off; # 设置后端服务器“Location”响应头和“Refresh”响应头的替换文本
  proxy_set_header X-Real-IP $remote_addr; # 获取用户的真实 IP 地址
  #后端的Web服务器可以通过 X-Forwarded-For 获取用户真实IP,多个 nginx 反代的情况下,例如 CDN。参见:http://gong1208.iteye.com/blog/1559835 和 http://bbs.linuxtone.org/thread-9050-1-1.html
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  #以下是一些反向代理的配置,可选。
  proxy_set_header Host $host; # 允许重新定义或者添加发往后端服务器的请求头。

  client_max_body_size 10m; #允许客户端请求的最大单文件字节数
  client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数,
  proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
  proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
  proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
  proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
  proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的设置
  proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
  proxy_temp_file_write_size 64k;
  #设定缓存文件夹大小,大于这个值,将从upstream服务器传
}

举例:

location ^~ /service/ {
  proxy_pass http://192.168.60.245:8080/;
  proxy_redirect      default;
  proxy_set_header    Host $host
  proxy_set_header    X-Real-IP $remote_addr;
  proxy_set_header    X-Forwarded-For  $proxy_add_x_forwarded_for;
}

简化:

location /proxy/ {
  proxy_pass http://backend.com/;
  proxy_redirect      default;
}

如何配置rewrite?

rewrite功能就是集合正则表达式和标志位实现url重写和重定向。rewrite只能放在server{}、location{}、if(){}块中,并且只能对域名后边的出去传递参数外的字符串起作用。如URL:
http://microloan-sms-platform.yxapp.xyz/proxy/sms/task/querydeleted?page=1&pagesize=10
只对/proxy/sms/task/querydeleted进行重写。

如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用proxy_pass反向代理。

表明看rewrite和location功能有点像,都能实现跳转,主要区别在于rewrite是在同一域名内更改获取资源的路径,而location是对一类路径做控制访问或反向代理,可以proxy_pass到其他机器。很多情况下rewrite也会写在location里,它们的执行顺序是:

  • 执行server块的rewrite指令
  • 执行location匹配
  • 执行选定的location中的rewrite指令

如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件;循环超过10次,则返回500 Internal Server Error错误。

rewrite规则后边,通常会带有flag标志位:

  • last : 相当于Apache的[L]标记,表示完成rewrite
  • break : 停止执行当前虚拟主机的后续rewrite指令集
  • redirect : 返回302临时重定向,地址栏会显示跳转后的地址
  • permanent : 返回301永久重定向,地址栏会显示跳转后的地址

lastbreak 区别:

  • last一般写在serverif中,而break一般使用在location
  • last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配
  • breaklast都能组织继续执行后面的rewrite指令

rewrite常用正则:

  • . : 匹配除换行符以外的任意字符
  • ? : 重复0次或1次
  • + : 重复1次或更多次
  • * : 重复0次或更多次
  • \d :匹配数字
  • ^ : 匹配字符串的开始
  • $ : 匹配字符串的介绍
  • {n} : 重复n次
  • {n,} : 重复n次或更多次
  • [c] : 匹配单个字符c
  • [a-z] : 匹配a-z小写字母的任意一个

可以使用()来进行分组,可以通过$1的形式来引用。

示例:

location /proxy/ {
        proxy_pass http://microloan-notification-web.yxapp.in;
        rewrite /proxy/(.*)$ /$1 break;
}

如何配置负载均衡?

示例:

upstream test.net{
   ip_hash;
   server 192.168.11.1:80;
   server 192.168.11.11:80  down;
   server 192.168.11.123:8009  max_fails=3  fail_timeout=20s;
   server 192.168.11.1234:8080;
}

upstream是Nginx的HTTP Upstream模块,这个模块通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡。
Nginx的负载均衡模块目前支持4种调度算法:

  • 轮询(默认)。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。Weight 指定轮询权值,Weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。
  • ip_hash。每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。
  • fair。这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的upstream_fair模块。
  • url_hash。此方法按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx 的hash软件包。

upstream可以设定每个后端服务器在负载均衡调度中的状态,支持的状态参数:

  • down,表示当前的server暂时不参与负载均衡
  • backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。
  • max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
  • fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用。

注,当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能是weight和backup。

如何设置页面缓存?

页面缓存设置指令:

  • proxy_cache_path : 指定缓存的路径和一些其他参数,缓存的数据存储在文件中,并且使用代理url的哈希值作为关键字与文件名。

      proxy_cache_path /data/nginx/cache/webserver levels=1:2 keys_zone=webserver:20m max_size=1g;

    levels参数指定缓存的子目录数。keys_zone指定活动的key和元数据存储在共享池(webserver为共享池名称,20m位共享池大小),inactive参数指定的时间内缓存的数据没有被请求则被删除,默认inactive为10分钟·max_size指定缓存空间的大小。

  • proxy_cache : 设置一个缓存区域的名称,一个相同的区域可以在不同的地方使用。
  • proxy_cache_valid : 为不同的应答设置不同的缓存时间。

如何设置读写分离?

server {
        listen       80;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
                proxy_pass http://192.128.133.202;
                if ($request_method = "PUT"){
                        proxy_pass http://192.128.18.201;
                }
        }
}

参考

Nginx能为前端开发带来什么?
前端工程师应该知道的Nginx
前端 Nginx https SSL proxy + 后端 Nginx http 应用的布署教程
nginx配置location总结及rewrite规则写法
nginx服务器安装及配置文件详解
http://freeloda.blog.51cto.com/2033581/1288553

查看原文

默凡 评论了文章 · 2018-09-02

前端nginx使用札记

nginx是什么?

nginx是俄罗斯人 Igor Sysoev为俄罗斯访问量第二的Rambler.ru站点开发的一个十分轻量级的HTTP服务器。它是一个高性能的HTTP和反向代理服务器,同时也可以作为IMAP/POP3/SMTP的代理服务器。nginx使用的是BSD许可。

Nginx 以事件驱动的方式编写,所以有非常好的性能,同时也是一个非常高效的反向代理、负载平衡。

Nginx 因为它的稳定性、丰富的模块库、灵活的配置和低系统资源的消耗而闻名。

nginx适合用来做mongrel clusters 的前端 HTTP 响应。

为什么要用nginx,nginx有什么特点?

nginx的特点

  • 核心特点:高并发请求的同时保持高效的服务
  • 热部署
  • 低内存消耗
  • 处理响应请求很快
  • 具有很高的可靠性

同时,nginx也可以实现高效的反向代理、负载均衡。

前端可以用nginx做些什么?

  • 搭建静态资源服务器
  • 反向代理分发后端服务(可以和nodejs搭配实现前后端分离)和跨域问题
  • 根据User Agent来重定向站点
  • 开发环境或测试环境切换(切换host)
  • url重写,使用rewrie规则本地映射
  • 资源内容篡改
  • 获取cookie做分流
  • 资源合并
  • gzip压缩
  • 压缩图片
  • sourceMap调试

如何安装nginx?

mac安装:

安装brew之后,执行命令:

$ sudo brew install nginx

windows安装

1.下载: nginx官网

  1. 解压运行:解压至c:\nginx,运行nginx.exe(即nginx -c conf\nginx.conf),默认使用80端口,日志见文件夹C:\nginx\logs
  2. 关闭:nginx -s stoptaskkill /F /IM nginx.exe > nul

【注意】以下皆以mac为例。

nginx如何启动、重启、关闭?

查看nginx版本:nginx -v

启动nginx服务:
方法一:运行命令:sudo brew services start nginx
方法二:运行命令:nginx
访问http://localhost:8080
出现如下界面则表示安装成功:
image

关闭nginx服务:
方法一:运行命令: sudo brew services stop nginx
方法二:运行命令: nginx -s stop
方法三:
运行命令:ps -ef | grep nginx,找到master对应的进程号。
快速停止:kill -TERM nginx进程号kill -INT nginx进程号
从容停止: kill -QUIT nginx进程号
强制停止所有nginx进程:pkill -9 nginx

重启nginx服务:
方法一:nginx -s reload
方法二: 平滑重启命令: kill -HUP nginx进程号

nginx信号控制:

  • TERM,INT 快速关闭
  • QUIT 从容关闭
  • HUP 平滑重启,重新加载配置文件
  • USR1 重新打开日志文件,在切割日志时用途较大
  • USR2 平滑升级可执行程序
  • WINCH 从容关闭工作进程

如何查看nginx的配置文件nginx.conf的路径和安装路径?

查看配置文件位置和测试配置文件语法:运行命令nginx -t:
image
查看nginx安装路径:
因为是使用brew安装的,所以使用brew命令:brew info nginx:
image

nginx.conf基本配置有哪些?

nginx配置文件主要分成四个部分:

  • main,全局设置,影响其它部分所有设置
  • server,主机服务相关设置,主要用于指定虚拟主机域名、IP和端口
  • location,URL匹配特定位置后的设置,反向代理、内容篡改相关设置
  • upstream,上游服务器设置,负载均衡相关配置

他们之间的关系式:server继承main,location继承server;upstream既不会继承指令也不会被继承。

如下是一份通用的配置和详解:

#定义 Nginx 运行的用户和用户组,默认由 nobody 账号运行, windows 下面可以注释掉。 
user  nobody; 

#nginx进程数,建议设置为等于CPU总核心数。可以和worker_cpu_affinity配合
worker_processes  1; 

#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#进程文件,window下可以注释掉
#pid        logs/nginx.pid;

# 一个nginx进程打开的最多文件描述符(句柄)数目,理论值应该是最多打开文件数(系统的值ulimit -n)与nginx进程数相除,
# 但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致。
worker_rlimit_nofile 65535;

#工作模式与连接数上限
events {
    # 参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; 
    # epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
   #use epoll;
   #connections 20000;  # 每个进程允许的最多连接数
   # 单个进程最大连接数(最大连接数=连接数*进程数)该值受系统进程最大打开文件数限制,需要使用命令ulimit -n 查看当前设置
   worker_connections 65535;
}

#设定http服务器
http {
    #文件扩展名与文件类型映射表
    #include 是个主模块指令,可以将配置文件拆分并引用,可以减少主配置文件的复杂度
    include       mime.types;
    #默认文件类型
    default_type  application/octet-stream;
    #charset utf-8; #默认编码

    #定义虚拟主机日志的格式
    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';
    
    #定义虚拟主机访问日志
    #access_log  logs/access.log  main;

    #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
    sendfile        on;
    #autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。

    #防止网络阻塞
    #tcp_nopush     on;

    #长连接超时时间,单位是秒,默认为0
    keepalive_timeout  65;

    # gzip压缩功能设置
    gzip on; #开启gzip压缩输出
    gzip_min_length 1k; #最小压缩文件大小
    gzip_buffers    4 16k; #压缩缓冲区
    gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
    gzip_comp_level 6; #压缩等级
    #压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
    gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
    gzip_vary on; //和http头有关系,加个vary头,给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩,所以根据客户端的HTTP头来判断,是否需要压缩
    #limit_zone crawler $binary_remote_addr 10m; #开启限制IP连接数的时候需要使用

    # http_proxy服务全局设置
    client_max_body_size   10m;
    client_body_buffer_size   128k;
    proxy_connect_timeout   75;
    proxy_send_timeout   75;
    proxy_read_timeout   75;
    proxy_buffer_size   4k;
    proxy_buffers   4 32k;
    proxy_busy_buffers_size   64k;
    proxy_temp_file_write_size  64k;
    proxy_temp_path   /usr/local/nginx/proxy_temp 1 2;

   # 设定负载均衡后台服务器列表 
    upstream  backend.com  { 
        #ip_hash; # 指定支持的调度算法
        # upstream 的负载均衡,weight 是权重,可以根据机器配置定义权重。weigth 参数表示权值,权值越高被分配到的几率越大。
        server   192.168.10.100:8080 max_fails=2 fail_timeout=30s ;  
        server   192.168.10.101:8080 max_fails=2 fail_timeout=30s ;  
    }

    #虚拟主机的配置
    server {
        #监听端口
        listen       80;
        #域名可以有多个,用空格隔开
        server_name  localhost fontend.com;
        # Server Side Include,通常称为服务器端嵌入
        #ssi on;
        #默认编码
        #charset utf-8;
        #定义本虚拟主机的访问日志
        #access_log  logs/host.access.log  main;
        
        # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
        location / {
            root   html;
            index  index.html index.htm;
        }
        
        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

       # 图片缓存时间设置
       location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ {
          expires 10d;
       }

       # JS和CSS缓存时间设置
       location ~ .*.(js|css)?$ {
          expires 1h;
       }

        #代理配置
        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #location /proxy/ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }

    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
}

location如何匹配?

示例:

location  = / {
  # 精确匹配 / ,主机名后面不能带任何字符串
  [ configuration A ] 
}

location  / {
  # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
  # 但是正则和最长字符串会优先匹配
  [ configuration B ] 
}

location /documents/ {
  # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
  # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
  [ configuration C ] 
}

location ~ /documents/Abc {
  # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
  # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
  [ configuration CC ] 
}

location ^~ /images/ {
  # 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
  [ configuration D ] 
}

location ~* \.(gif|jpg|jpeg)$ {
  # 匹配所有以 gif,jpg或jpeg 结尾的请求
  # 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则
  [ configuration E ] 
}

location /images/ {
  # 字符匹配到 /images/,继续往下,会发现 ^~ 存在
  [ configuration F ] 
}

location /images/abc {
  # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在
  # F与G的放置顺序是没有关系的
  [ configuration G ] 
}

location ~ /images/abc/ {
  # 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用
    [ configuration H ] 
}

location ~* /js/.*/\.js
  • =开头表示精确匹配
  • ^~ 开头表示uri以某个常规字符串开头,不是正则匹配
  • ~ 开头表示区分大小写的正则匹配;
  • ~* 开头表示不区分大小写的正则匹配
  • / 通用匹配, 如果没有其它匹配,任何请求都会匹配到

优先级:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (/)

如何配置反向代理?

详解:

# 对 “/” 启用反向代理
location / {
  proxy_pass http://127.0.0.1:3000;  # 设置要代理的 uri,注意最后的 /。可以是 Unix 域套接字路径,也可以是正则表达式。
  proxy_redirect off; # 设置后端服务器“Location”响应头和“Refresh”响应头的替换文本
  proxy_set_header X-Real-IP $remote_addr; # 获取用户的真实 IP 地址
  #后端的Web服务器可以通过 X-Forwarded-For 获取用户真实IP,多个 nginx 反代的情况下,例如 CDN。参见:http://gong1208.iteye.com/blog/1559835 和 http://bbs.linuxtone.org/thread-9050-1-1.html
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  #以下是一些反向代理的配置,可选。
  proxy_set_header Host $host; # 允许重新定义或者添加发往后端服务器的请求头。

  client_max_body_size 10m; #允许客户端请求的最大单文件字节数
  client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数,
  proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
  proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
  proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
  proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
  proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的设置
  proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
  proxy_temp_file_write_size 64k;
  #设定缓存文件夹大小,大于这个值,将从upstream服务器传
}

举例:

location ^~ /service/ {
  proxy_pass http://192.168.60.245:8080/;
  proxy_redirect      default;
  proxy_set_header    Host $host
  proxy_set_header    X-Real-IP $remote_addr;
  proxy_set_header    X-Forwarded-For  $proxy_add_x_forwarded_for;
}

简化:

location /proxy/ {
  proxy_pass http://backend.com/;
  proxy_redirect      default;
}

如何配置rewrite?

rewrite功能就是集合正则表达式和标志位实现url重写和重定向。rewrite只能放在server{}、location{}、if(){}块中,并且只能对域名后边的出去传递参数外的字符串起作用。如URL:
http://microloan-sms-platform.yxapp.xyz/proxy/sms/task/querydeleted?page=1&pagesize=10
只对/proxy/sms/task/querydeleted进行重写。

如果相对域名或参数字符串起作用,可以使用全局变量匹配,也可以使用proxy_pass反向代理。

表明看rewrite和location功能有点像,都能实现跳转,主要区别在于rewrite是在同一域名内更改获取资源的路径,而location是对一类路径做控制访问或反向代理,可以proxy_pass到其他机器。很多情况下rewrite也会写在location里,它们的执行顺序是:

  • 执行server块的rewrite指令
  • 执行location匹配
  • 执行选定的location中的rewrite指令

如果其中某步URI被重写,则重新循环执行1-3,直到找到真实存在的文件;循环超过10次,则返回500 Internal Server Error错误。

rewrite规则后边,通常会带有flag标志位:

  • last : 相当于Apache的[L]标记,表示完成rewrite
  • break : 停止执行当前虚拟主机的后续rewrite指令集
  • redirect : 返回302临时重定向,地址栏会显示跳转后的地址
  • permanent : 返回301永久重定向,地址栏会显示跳转后的地址

lastbreak 区别:

  • last一般写在serverif中,而break一般使用在location
  • last不终止重写后的url匹配,即新的url会再从server走一遍匹配流程,而break终止重写后的匹配
  • breaklast都能组织继续执行后面的rewrite指令

rewrite常用正则:

  • . : 匹配除换行符以外的任意字符
  • ? : 重复0次或1次
  • + : 重复1次或更多次
  • * : 重复0次或更多次
  • \d :匹配数字
  • ^ : 匹配字符串的开始
  • $ : 匹配字符串的介绍
  • {n} : 重复n次
  • {n,} : 重复n次或更多次
  • [c] : 匹配单个字符c
  • [a-z] : 匹配a-z小写字母的任意一个

可以使用()来进行分组,可以通过$1的形式来引用。

示例:

location /proxy/ {
        proxy_pass http://microloan-notification-web.yxapp.in;
        rewrite /proxy/(.*)$ /$1 break;
}

如何配置负载均衡?

示例:

upstream test.net{
   ip_hash;
   server 192.168.11.1:80;
   server 192.168.11.11:80  down;
   server 192.168.11.123:8009  max_fails=3  fail_timeout=20s;
   server 192.168.11.1234:8080;
}

upstream是Nginx的HTTP Upstream模块,这个模块通过一个简单的调度算法来实现客户端IP到后端服务器的负载均衡。
Nginx的负载均衡模块目前支持4种调度算法:

  • 轮询(默认)。每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响。Weight 指定轮询权值,Weight值越大,分配到的访问机率越高,主要用于后端每个服务器性能不均的情况下。
  • ip_hash。每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题。
  • fair。这是比上面两个更加智能的负载均衡算法。此种算法可以依据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载Nginx的upstream_fair模块。
  • url_hash。此方法按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身是不支持url_hash的,如果需要使用这种调度算法,必须安装Nginx 的hash软件包。

upstream可以设定每个后端服务器在负载均衡调度中的状态,支持的状态参数:

  • down,表示当前的server暂时不参与负载均衡
  • backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。
  • max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
  • fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用。

注,当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能是weight和backup。

如何设置页面缓存?

页面缓存设置指令:

  • proxy_cache_path : 指定缓存的路径和一些其他参数,缓存的数据存储在文件中,并且使用代理url的哈希值作为关键字与文件名。

      proxy_cache_path /data/nginx/cache/webserver levels=1:2 keys_zone=webserver:20m max_size=1g;

    levels参数指定缓存的子目录数。keys_zone指定活动的key和元数据存储在共享池(webserver为共享池名称,20m位共享池大小),inactive参数指定的时间内缓存的数据没有被请求则被删除,默认inactive为10分钟·max_size指定缓存空间的大小。

  • proxy_cache : 设置一个缓存区域的名称,一个相同的区域可以在不同的地方使用。
  • proxy_cache_valid : 为不同的应答设置不同的缓存时间。

如何设置读写分离?

server {
        listen       80;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
                proxy_pass http://192.128.133.202;
                if ($request_method = "PUT"){
                        proxy_pass http://192.128.18.201;
                }
        }
}

参考

Nginx能为前端开发带来什么?
前端工程师应该知道的Nginx
前端 Nginx https SSL proxy + 后端 Nginx http 应用的布署教程
nginx配置location总结及rewrite规则写法
nginx服务器安装及配置文件详解
http://freeloda.blog.51cto.com/2033581/1288553

查看原文

默凡 赞了文章 · 2018-08-27

前端每日实战:118# 视频演示如何用纯 CSS 创作一个沙漏 loader

图片描述

效果预览

按下右侧的“点击预览”按钮可以在当前页面预览,点击链接可以全屏预览。

https://codepen.io/comehope/pen/VGegxr

可交互视频

此视频是可以交互的,你可以随时暂停视频,编辑视频中的代码。

请用 chrome, safari, edge 打开观看。

https://scrimba.com/p/pEgDAM/cVRr9cp

源代码下载

每日前端实战系列的全部源代码请从 github 下载:

https://github.com/comehope/front-end-daily-challenges

代码解读

定义 dom,容器中包含 2 个元素,分别代表沙漏的上半部和下半部:

<div class="loader">
    <span class="top"></span>
    <span class="bottom"></span>
</div>

居中显示:

body {
    margin: 0;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: gainsboro;
}

定义容器尺寸,并设置子元素整体布局:

.loader {
    width: 4.3em;
    height: 9.8em;
    font-size: 10px;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
}

画出 2 个正方形:

.top,
.bottom {
    width: 3.5em;
    height: 3.5em;
    border-style: solid;
    border-color: saddlebrown;
}

通过边框、圆角和旋转,把 2 个正方形变成沙漏形状:

.top,
.bottom {
    border-width: 0.2em 0.2em 0.6em 0.6em;
    border-radius: 50% 100% 50% 30%;
}

.top {
    transform: rotate(-45deg);
}

.bottom {
    transform: rotate(135deg);
}

用伪元素画出沙子,上部的沙子的顶部是大圆弧,下部的沙子的顶部是小圆弧:

.top::before,
.bottom::before {
    content: '';
    position: absolute;
    width: inherit;
    height: inherit;
    background-color: deepskyblue;
}

.top::before {
    border-radius: 0 100% 0 0;
}

.bottom::before {
    border-radius: 0 0 0 35%;
}

定义沙子的动画属性:

.top::before,
.bottom::before {
    animation: 2s linear infinite;
}

增加沙子从沙漏的上半部落下的动画效果:

.top::before {
    animation-name: drop-sand;
}

@keyframes drop-sand {
    to {
        transform: translate(-2.5em, 2.5em);
    }
}

增加沙子的沙漏在下半部堆积的动画效果:

.bottom::before {
    transform: translate(2.5em, -2.5em);
    animation-name: fill-sand;
}

@keyframes fill-sand {
    to {
        transform: translate(0, 0);
    }
}

隐藏沙漏上半部和下半部容器外的部分,此时上面 2 个动画的叠加效果是沙子从上半部漏下,慢慢在下半部堆积:

.top,
.bottom {
    overflow: hidden;
}

用外层容器的伪元素制作一个窄长条,模拟流动的沙子:

.loader::after {
    content: '';
    position: absolute;
    width: 0.2em;
    height: 4.8em;
    background-color: deepskyblue;
    top: 1em;
}

增加沙子流动的动画效果:

.loader::after {
    animation: flow 2s linear infinite;
}

@keyframes flow {
    10%, 100% {
        transform: translateY(3.2em);
    }
}

最后,增加沙漏的翻转动画:

.loader {
    animation: rotating 2s linear infinite;
}

@keyframes rotating {
    0%, 90% {
        transform: rotate(0);
    }
    
    100% {
        transform: rotate(0.5turn);
    }
}

大功告成!

查看原文

赞 22 收藏 12 评论 4

默凡 收藏了文章 · 2018-08-14

手摸手,带你用合理的姿势使用webpack4(上)

本文作者来自 华尔街见闻技术团队 - 花裤衩

前几天 webpack 作者 Tobias Koppers 发布了一篇新的文章 webpack 4.0 to 4.16: Did you know?(需翻墙),总结了一下webpack 4发布以来,做了哪些调整和优化。
并且说自己正在着手开发 webpack 5

Oh you are still on webpack 3. I’m sorry, what is blocking you? We already working on webpack 5, so your stack might be outdated soon…

翻译成中文就是:

正好我也在使用一个文档生成工具 docz(安利一波) 也最低需要webpack 4+,新版webpack性能提高了不少,而且webpack 4 都已经发布五个多月了,想必应该已经没什么坑了,应该可以安心的按照别人写的升级攻略升级了。之前一直迟迟不升级完全是被去年被 webpack 3 坑怕了。它在 code splitting 的情况下 CommonsChunkPlugin会完全失效。过了好一段时间才修复,欲哭无泪。

所以这次我等了快大半年才准备升级到webpack 4但万万没想到还是遇到了不少的问题! 有很多之前遗留的问题还是没有很好地解决。但最主要的问题还是它的文档有所欠缺,已经废除了的东西如commonsChunkPlugin还在官方文档中到处出现,很多重要的东西却一笔带过,甚至没写,需要用户自己去看源码才能解决。

还比如在v4.16.0版本中废除了optimization.occurrenceOrderoptimization.namedChunksoptimization.hashedModuleIdsoptimization.namedModules 这几个配置项,替换成了optimization.moduleIdsoptimization.chunkIds,但文档完中全没有任何体现,所以你在新版本中还按照文档那样配置其实是没有任何效果的。

最新最完整的文档还是看他项目的配置WebpackOptions.json,强烈建议遇到不清楚的配置项可以看这个,因为它一定保证是和最新代码同步的。

吐槽了这么多,我们言归正传。由于本次手摸手篇幅有些长,所以拆解成了上下两篇文章:

  • 上篇 -- 就是普通的在webpack 3的基础上升级,要做哪些操作和遇到了哪些坑
  • 下篇 -- 是在webpack 4下怎么合理的打包和拆包,并且如何最大化利用 long term caching

本文章不是手摸手从零教你 webpack 配置,所以并不会讲太多很基础的配置问题。比如如何处理 css 文件,如何配置 webpack-dev-server,讲述 file-loader 和 url-loader 之间的区别等等,有需求的推荐看 官方文档 或者 survivejs 出的一个系列教程。或者推荐看我司的另一篇 wbepack 入门文章,已同步到 webpack4 传送门

升级篇

前言

我一直认为模仿和借鉴是学习一个新东西最高效的方法。所以我建议还是通过借鉴一些成熟的 webpack 配置比较好。比如你项目是基于 react 生态圈的话可以借鉴 create-react-app ,下载之后npm run eject 就可以看到它详细的 webpack 配置了。vue 的话由于新版vue cli不支持 eject了,而且改用 webpack-chain来配置,所以借鉴起来可能会不太方便,主要配置 地址。觉得麻烦的话你可以直接借鉴 vue-element-admin配置。或者你想自己发挥,你可以借鉴 webpack 官方的各种 examples,来组合你的配置。

升级 webpack

首先将 webpack 升级到 4 之后,直接运行webpack --xxx是不行的,因为新版本将命令行相关的东西单独拆了出去封装成了webpack-cli。会报如下错误:

The CLI moved into a separate package: webpack-cli.
Please install webpack-cli in addition to webpack itself to use the CLI.

所有你需要安装npm install webpack-cli -D -S。你也可将它安装在全局。

同时新版 webpack 需要Node.js 的最低支持版本为 6.11.5不要忘了升级。如果还需要维护老项目可以使用 nvm 来做一下 node 版本管理。

升级所有依赖

因为webpack4改了 它的hook api ,所以所有的loadersplugins都需要升级才能够适配。

可以使用命令行 npm outdated,列出所以可以更新的包。免得再一个个去npm找相对于的可用版本了。

反正把devDependencies的依赖都升级一下,总归不会有错。

带来的变化

其实这次升级带来了不少改变,但大部分其实对于普通用户来说是不需要关注的,比如这次升级带来的功能SideEffectsModule Type’s IntroducedWebAssembly Support,基本平时是用不到的。我们主要关注那些对我们影响比较大的改动如:optimization.splitChunks代替原有的CommonsChunkPlugin(下篇文章会着重介绍),和Better Defaults-mode更好的默认配置,这是大家稍微需要关注一下的。

如果想进一步了解 Tree ShakingSideEffects的可见文末拓展阅读。
上图参考 Webpack 4 进阶

默认配置

webpack 4 引入了零配置的概念,被 parcel 刺激到了。 不管效果怎样,这改变还是值得称赞的。

最近又新出了 Fastpack 可以关注一下。

言归正题,我们来看看 webpack 默认帮我们做了些什么?

development 模式下,默认开启了NamedChunksPluginNamedModulesPlugin方便调试,提供了更完整的错误信息,更快的重新编译的速度。

module.exports = {
+ mode: 'development'
- devtool: 'eval',
- plugins: [
-   new webpack.NamedModulesPlugin(),
-   new webpack.NamedChunksPlugin(),
-   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}

production 模式下,由于提供了splitChunksminimize,所以基本零配置,代码就会自动分割、压缩、优化,同时 webpack 也会自动帮你 Scope hoistingTree-shaking

module.exports = {
+  mode: 'production',
-  plugins: [
-    new UglifyJsPlugin(/* ... */),
-    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
-    new webpack.optimize.ModuleConcatenationPlugin(),
-    new webpack.NoEmitOnErrorsPlugin()
-  ]
}

webpack 一直以来最饱受诟病的就是其配置门槛极高,配置内容极其复杂和繁琐,容易让人从入门到放弃,而它的后起之秀如 rollup、parcel 等均在配置流程上做了极大的优化,做到开箱即用,所以webpack 4 也从中借鉴了不少经验来提升自身的配置效率。愿世间再也不需要 webpack 配置工程师

html-webpack-plugin

用最新版本的的 html-webpack-plugin你可能还会遇到如下的错误:

throw new Error('Cyclic dependency' + nodeRep)

产生这个 bug 的原因是循环引用依赖,如果你没有这个问题可以忽略。

目前解决方案可以使用 Alpha 版本,npm i --save-dev html-webpack-plugin@next

或者加入chunksSortMode: 'none'就可以了。

但仔细查看文档发现设置成chunksSortMode: 'none'这样是会有问题的。

Allows to control how chunks should be sorted before they are included to the HTML.

这属性会决定你 chunks 的加载顺序,如果设置为none,你的 chunk 加载在页面中加载的顺序就不能够保证了,可能会出现样式被覆盖的情况。比如我在app.css里面修改了一个第三方库element-ui的样式,通过加载顺序的先后来覆盖它,但由于设置为了none,打包出来的结果变成了这样:

<link href="/app.8945fbfc.css" rel="stylesheet">
<link href="/chunk-elementUI.2db88087.css" rel="stylesheet">

app.css被先加载了,之前写的样式覆盖就失效了,除非你使用important或者其它 css 权重的方式覆盖它,但这明显是不太合理的。
vue-cli正好也有这个相关 issue,尤雨溪也在不使用@next版本的基础上 hack 了它,有兴趣的可以自己研究一下,本人在项目中直接使用了@next版本,也没遇到其它什么问题(除了不兼容 webpack 的 prefetch/preload 相关 issue)。两种方案都可以,自行选择。

其它 html-webpack-plugin 的配置和之前使用没有什么区别。

mini-css-extract-plugin

与 extract-text-webpack-plugin 区别

由于webpack4对 css 模块支持的完善以及在处理 css 文件提取的方式上也做了些调整,所以之前我们一直使用的extract-text-webpack-plugin也完成了它的历史使命,将让位于mini-css-extract-plugin

使用方式也很简单,大家看着 文档 抄就可以了。

它与extract-text-webpack-plugin最大的区别是:它在code spliting的时候会将原先内联写在每一个 js chunk bundle的 css,单独拆成了一个个 css 文件。

原先 css 是这样内联在 js 文件里的:

将 css 独立拆包最大的好处就是 js 和 css 的改动,不会影响对方。比如我改了 js 文件并不会导致 css 文件的缓存失效。而且现在它自动会配合optimization.splitChunks的配置,可以自定义拆分 css 文件,比如我单独配置了element-ui作为单独一个bundle,它会自动也将它的样式单独打包成一个 css 文件,不会像以前默认将第三方的 css 全部打包成一个几十甚至上百 KB 的app.xxx.css文件了。

压缩与优化

打包 css 之后查看源码,我们发现它并没有帮我们做代码压缩,这时候需要使用 optimize-css-assets-webpack-plugin 这个插件,它不仅能帮你压缩 css 还能优化你的代码。

//配置
optimization: {
  minimizer: [new OptimizeCSSAssetsPlugin()];
}

如上图测试用例所示,由于optimize-css-assets-webpack-plugin这个插件默认使用了 cssnano 来作 css 优化,
所以它不仅压缩了代码、删掉了代码中无用的注释、还去除了冗余的 css、优化了 css 的书写顺序,优化了你的代码 margin: 10px 20px 10px 20px; =>margin:10px 20px;。同时大大减小了你 css 的文件大小。更多优化的细节见文档

contenthash

但使用 MiniCssExtractPlugin 有一个需求特别注意的地方,在默认文档中它是这样配置的:

new MiniCssExtractPlugin({
  // Options similar to the same options in webpackOptions.output
  // both options are optional
  filename: devMode ? "[name].css" : "[name].[hash].css",
  chunkFilename: devMode ? "[id].css" : "[id].[hash].css"
});
简单说明一下: filename 是指在你入口文件entry中引入生成出来的文件名,而chunkname是指那些未被在入口文件entry引入,但又通过按需加载(异步)模块的时候引入的文件。

copy 如上代码使用之后发现情况不对!每次改动一个xx.js文件,它对应的 css 虽然没做任何改动,但它的 文件 hash 还是会发生变化。仔细对比发现原来是 hash 惹的祸。 6.f3bfa3af.css => 6.40bc56f6.css

但我这是根据官方文档来写的!为什么还有问题!后来在文档的最最最下面发下了这么一段话!

For long term caching use filename: [contenthash].css. Optionally add [name].

非常的不理解,这么关键的一句话会放在 Maintainers 还后面的地方,默认写在配置里面提示大家不是更好?有热心群众已经开了一个pr,将文档默认配置为 contenthashchunkhash => contenthash相关 issue

这个真的蛮过分的,稍不注意就会让自己的 css 文件缓存无效。而且很多用户平时修改代码的时候都不会在意自己最终打包出来的 dist文件夹中到底有哪些变化。所以这个问题可能就一直存在了。浪费了多少资源!人艰不拆!大家觉得 webpack 难用不是没道理的。

这里再简单说明一下几种 hash 的区别:

  • hash

hash 和每次 build有关,没有任何改变的情况下,每次编译出来的 hash都是一样的,但当你改变了任何一点东西,它的hash就会发生改变。

简单理解,你改了任何东西,hash 就会和上次不一样了。

  • chunkhash

chunkhash是根据具体每一个模块文件自己的的内容包括它的依赖计算所得的hash,所以某个文件的改动只会影响它本身的hash,不会影响其它文件。

  • contenthash

它的出现主要是为了解决,让css文件不受js文件的影响。比如foo.cssfoo.js引用了,所以它们共用相同的chunkhash值。但这样子是有问题的,如果foo.js修改了代码,css文件就算内容没有任何改变,由于是该模块的 hash 发生了改变,其css文件的hash也会随之改变。

这个时候我们就可以使用contenthash了,保证即使css文件所处的模块里有任何内容的改变,只要 css 文件内容不变,那么它的hash就不会发生变化。

contenthash 你可以简单理解为是 moduleId + content 所生成的 hash

热更新速度

其实相对 webpack 线上打包速度,我更关心的本地开发热更新速度,毕竟这才是和我们每一个程序员每天真正打交道的东西,打包一般都会扔给CI自动执行,而且一般项目每天也不会打包很多次。

webpack 4一直说自己更好的利用了cache提高了编译速度,但实测发现是有一定的提升,但当你一个项目,路由懒加载的页面多了之后,50+之后,热更新慢的问题会很明显,之前的文章中也提到过这个问题,原以为新版本会解决这个问题,但并没有。

不过你首先要排斥你的热更新慢不是,如:

  • 没有使用合理的 Devtool souce map 导致
  • 没有正确使用 exclude/include 处理了不需要处理的如node_modules
  • 在开发环境不要压缩代码UglifyJs、提取 css、babel polyfill、计算文件 hash 等不需要的操作

旧方案

最早的方案是开发环境中不是用路由懒加载了,只在线上环境中使用。封装一个_import函数,通过环境变区分是否需要懒加载。

开发环境:

module.exports = file => require("@/views/" + file + ".vue").default;

生成环境:

module.exports = file => () => import("@/views/" + file + ".vue");

但由于 webpack import实现机制问题,会产生一定的副作用。如上面的写法就会导致@/views/下的 所有.vue 文件都会被打包。不管你是否被依赖引用了,会多打包一些可能永远都用不到 js 代码。 相关 issue

目前新的解决方案思路还是一样的,只在生成模式中使用路由懒加载,本地开发不使用懒加载。但换了一种没副作用的实现方式。

新方案

使用babelpluginsbabel-plugin-dynamic-import-node。它只做一件事就是:将所有的import()转化为require(),这样就可以用这个插件将所有异步组件都用同步的方式引入了,并结合 BABEL_ENV 这个bebel环境变量,让它只作用于开发环境下。将开发环境中所有import()转化为require(),这种方案解决了之前重复打包的问题,同时对代码的侵入性也很小,你平时写路由的时候只需要按照官方文档路由懒加载的方式就可以了,其它的都交给babel来处理,当你不想用这个方案的时候,也只需要将它从babelplugins中移除就可以了。

具体代码:

首先在package.json中增加BABEL_ENV

"dev": "BABEL_ENV=development webpack-dev-server XXXX"

接着在.babelrc只能加入babel-plugin-dynamic-import-node这个plugins,并让它只有在development模式中才生效。

{
  "env": {
    "development": {
      "plugins": ["dynamic-import-node"]
    }
  }
}

之后就大功告成了,路由只要像平时一样写就可以了。文档

 { path: '/login', component: () => import('@/views/login/index')}

这样能大大提升你热更新的速度。基本两百加页面也能在2000ms的热跟新完成,基本做到无感刷新。当然你的项目本身就不大页面也不多,完全没必要搞这些。当你的页面变化跟不是你写代码速度的时候再考虑也不迟。

打包速度

webpack 4 在项目中实际测了下,普遍能提高 20%~30%的打包速度。

本文不准备太深入的讲解这部分内容,详细的打包优化速度可以参考 slack 团队的这篇文章,掘金还有译文.

这里有几个建议来帮你加速 webpack 的打包速度。

首先你需要知道你目前打包慢,是慢在哪里。

我们可以用 speed-measure-webpack-plugin 这个插件,它能监控 webpack 每一步操作的耗时。如下图:

可以看出其实大部分打包花费的时间是在Uglifyjs压缩代码。和前面的提升热更新的切入点差不多,查看source map的正确与否,exclude/include的正确使用等等。

使用新版的UglifyJsPlugin的时候记住可以加上cache: trueparall: true,可以提搞代码打包压缩速度。更多配置可以参考 文档 或者 vue-cli 的 配置

编译的时候还有还有一个很慢的原因是那些第三方库。比如echartselement-ui其实都非常的大,比如echarts打包完也还有 775kb。所以你想大大提高编译速度,可以将这些第三方库 externals 出去,使用script的方式引入,或者使用 dll的方式打包。经测试一般如echarts这样大的包可以节省十几秒到几十秒不等。

还有可以使用一些并行执行 webpack 的库:如parallel-webpackhappypack

顺便说一下,升级一下node可能有惊喜。前不久将CI里面的 node 版本依赖从 6.9.2 => 8.11.3,打包速度直接提升了一分多钟。

总之我觉得打包时间控制在差不多的范围内就可以了,没必要过分的优化。可能你研究了半天,改了一堆参数发现其实也就提升了几秒,但维护成本上去了,得不偿失。还不如升级 node、升级 webpack、升级你的编译环境的硬件水平来的实在和简单。

比如我司CI使用的是腾讯云普通的的 8 核 16g 的机器,这个项目也是一个很大的后台管理项目 200+页面,引用了很多第三方的库,但没有使用什么happypackdll,只是用了最新版的webpack4node@8.11.3
编译速度稳定在两分多钟,完全不觉得有什么要优化的必要。

Tree-Shaking

这其实并不是 webpack 4 才提出来的概念,最早是 rollup 提出来并实现的,后来在 webpack 2 中就实现了,本次在 webpack 4 只是增加了 JSON Tree ShakingsideEffects能让你能更好的

不过这里还是要提一下,默认 webpack 是支持Tree-Shaking的,但在你的项目中可能会因为babel的原因导致它失效。

因为Tree Shaking这个功能是基于ES6 modules 的静态特性检测,来找出未使用的代码,所以如果你使用了 babel 插件的时候,如:babel-preset-env,它默认会将模块打包成commonjs,这样就会让Tree Shaking失效了。

其实在 webpack 2 之后它自己就支持模块化处理。所以只要让 babel 不transform modules就可以了。配置如下:

// .babelrc
{
  "presets": [
    ["env", {
      modules: false,
      ...
    }]
  ]
}

顺便说一下都 8102 年了,请不要在使用babel-preset-esxxxx系列了,请用babel-preset-env,相关文章 再见,babel-preset-2015

下部分内容

拓展阅读

查看原文

默凡 回答了问题 · 2018-08-14

解决关于vueJS,input框使用:value进行绑定的数据不能实时更新。但是使用v-model确实时更新的疑问?

最好不要用value吧,value是input框的自有属性,可以换成别的名字试试看呐

关注 2 回答 1

默凡 收藏了文章 · 2018-08-06

Sequelize 中文文档 v4 - Basic usage - 基本用法

Basic usage - 基本用法

此系列文章的应用示例已发布于 GitHub: sequelize-docs-Zh-CN. 可以 Fork 帮助改进或 Star 关注更新. 欢迎 Star.

在开始之前,你首先必须创建一个 Sequelize 的实例。 像下面这样:

const sequelize = new Sequelize('database', 'username'[, 'password'])

这将会保存要传递的数据库凭据并提供所有进一步的方法。此外,你还可以指定非默认的主机或端口:

const sequelize = new Sequelize('database', 'username', 'password', {
  host: "my.server.tld",
  port: 12345
})

如果你没有密码:

const sequelize = new Sequelize('database', 'username')
// 或
const sequelize = new Sequelize('database', 'username', null)

你也可以使用连接字符串:

const sequelize = new Sequelize('mysql://user:pass@example.com:9821/dbname', {
  // 更多选项请看下一节
})

选项

除了主机和端口,Sequelize 还提供了一大堆选项。它们在这:

const sequelize = new Sequelize('database', 'username', 'password', {
  // 自定义主机; 默认值: localhost
  host: 'my.server.tld',
 
  // 自定义端口; 默认值: 3306
  port: 12345,
 
  // 自定义协议
  // - 默认值: 'tcp'
  // - 版本: v1.5.0
  // - 仅限 postgres, 用于 heroku
  protocol: null,
 
  // 禁用日志; 默认值: console.log
  logging: false,
 
  // 数据库的 sql 方言
  // - 当前支持: 'mysql', 'sqlite', 'postgres', 'mssql'
  dialect: 'mysql',
 
  // 你还可以将任何方言选项传递到底层方言库
  // - 默认是空
  // - 当前支持: 'mysql', 'postgres', 'mssql'
  dialectOptions: {
    socketPath: '/Applications/MAMP/tmp/mysql/mysql.sock',
    supportBigNumbers: true,
    bigNumberStrings: true
  },
 
  // sqlite 的存储引擎
  // - 默认值 ':memory:'
  storage: 'path/to/database.sqlite',
 
  // 禁止将未定义的值插入为NULL
  // - 默认值: false
  omitNull: true,
 
  // 是否使用本地库的标志
  // 如果是 'pg' -- 设置为 true 将允许 SSL 支持
  // - 默认值: false
  native: true,
 
  // 指定在调用 sequelize.define 时使用的选项
  // 如下示例:
  //   define: {timestamps: false}
  // 这基本等同于:
  //   sequelize.define(name, attributes, { timestamps: false })
  // 没有必要像这样去设置每个定义的时间戳选项
  // 下面你看到的这些可能设置的键. 本章中都进行了说明
  define: {
    underscored: false
    freezeTableName: false,
    syncOnAssociation: true,
    charset: 'utf8',
    dialectOptions: {
      collate: 'utf8_general_ci'
    },
    timestamps: true
  },
 
  // 类似于同步:你可以定义始终强制同步模型
  sync: { force: true },
 
  // 每次关联后进行同步(见下文)。 如果设置为 false,则需要在设置所有关联后手动进行同步。 默认值: true
  syncOnAssociation: true,
 
  // 使用连接池来减少数据库连接超载并提高速度
  // 当前仅支持 mysql 和 postgresql (从 v1.5.0 开始)
  pool: { max: 5, idle: 30},
 
  // 用于确定如何根据 [lingo project](https://github.com/visionmedia/lingo) 将单词翻译成单数形式或复数形式
  // 选项为: en [默认], es
  language: 'en',

  // 每个事务的隔离级别. 默认是 REPEATABLE_READ
  // 可用选项:
  // READ_UNCOMMITTED
  // READ_COMMITTED
  // REPEATABLE_READ
  // SERIALIZABLE
  isolationLevel: Transaction.ISOLATION_LEVELS.REPEATABLE_READ
})

提示: 你可以通过传递一个方法为日志部分设置一个自定义方法。第一个参数是将被记录的字符串 。

读取复制

Sequelize 支持读取复制,即在要执行 SELECT 查询时可以连接到多个服务器。 当你读取复制时,你指定一个或多个服务器作为读取副本,一个服务器充当写入主机,它处理所有写入和更新,并将其传播到副本(请注意,实际的复制进程为 不是 由 Sequelize 处理,而应该在 MySql 中设置)。

const sequelize = new Sequelize('database', null, null, {
  dialect: 'mysql',
  port: 3306
  replication: {
    read: [
      { host: '8.8.8.8', username: 'anotherusernamethanroot', password: 'lolcats!' },
      { host: 'localhost', username: 'root', password: null }
    ],
    write: { host: 'localhost', username: 'root', password: null }
  },
  pool: { // 如果要覆盖用于读取池的选项,可以在此处进行
    max: 20,
    idle: 30000
  },
})

如果你有适用于所有副本的常规设置,则不需要为每个实例单独提供它们。在上面的代码中,数据库名称和端口被传播到所有副本。对于用户和密码也是如此, 如果你把它们用于任何一个副本。每个副本都有以下选项:hostportusernamepassworddatabase

Sequelize 使用池来管理与副本的连接。 默认选项为:

{
  max: 5,
  min: 0,
  idle: 10000,
  acquire: 10000,
  evict: 60000,
  handleDisconnects: true  
}

如果要修改这些,可以在实例化 Sequelize 时作为选项传递池,如上所示。

注意: 读复制当前只适用于MySQL!

方言

随着 Sequelize 1.6.0 的发布,库可以独立于特定的方言。这意味着您必须自己添加相应的连接器库到您的项目。版本 1.7.0 stable 已经与连接器库(sequelize-mysql,sequelize-postgres等)捆绑在一起发布,但是这些软件包没有被维护,并且不会向2.0.0发布。

MySQL

为了使 Sequelize 与 MySQL 完美结合,您需要安装 mysql2@^1.0.0-rc.10 或更高版本。 一旦完成,你可以这样使用它:

const sequelize = new Sequelize('database', 'username', 'password', {
  dialect: 'mysql'
})

注意: 您可以通过设置 dialectOptions 参数将选项直接传递给方言库. 查看 Options
获取例子 (目前只支持mysql).

SQLite

对于 SQLite 兼容性,您将需要 sqlite3 @〜3.0.0。 配置 Sequelize 如下所示:

const sequelize = new Sequelize('database', 'username', 'password', {
  // 设置成 sqlite
  dialect: 'sqlite',
 
  // sqlite 的存储引擎
  // - default ':memory:'
  storage: 'path/to/database.sqlite'
})

或者您也可以使用连接字符串以及路径:

const sequelize = new Sequelize('sqlite:/home/abs/path/dbname.db')
const sequelize = new Sequelize('sqlite:relativePath/dbname.db')

PostgreSQL

PostgreSQL 的库是 pg@^5.0.0 || ^6.0.0 || ^7.0.0 你只需要定义方言:

const sequelize = new Sequelize('database', 'username', 'password', {
  // 定义为 postgres
  dialect: 'postgres'
})

MSSQL

MSSQL 的库是 tedious@^1.7.0 你只需要定义方言:

const sequelize = new Sequelize('database', 'username', 'password', {
  dialect: 'mssql'
})

执行原始 SQL 查询

由于常常使用简单的方式来执行原始/已经准备好的SQL查询,所以可以使用“sequelize.query”函数。

这是它如何工作的:

// 原始查询的参数
sequelize.query('your query', [, options])

// 简单的例子
sequelize.query("SELECT * FROM myTable").then(myTableRows => {
  console.log(myTableRows)
})

// 如果要返回 sequelize 实例,请使用模型选项。
// 这样,你可以轻松地将查询映射到预定义的sequelize模型,例如:
sequelize
  .query('SELECT * FROM projects', { model: Projects })
  .then(projects => {
    // 每个记录现在将映射到项目的模型。
    console.log(projects)
  })


// 选项是具有以下键的对象:
sequelize
  .query('SELECT 1', {
    // 用于记录查询的函数(或false)
    // 每个发送到服务器的SQL查询都会调用
    logging: console.log,

    // 如果 plain 是 TRUE ,则 sequelize 将只返回结果集的第一条记录。
    // 如果是 FALSE, 则是全部记录。
    plain: false,

    // 如果你没有查询的模型定义,请将其设置为true。
    raw: false
  })

// 注意第二个参数为null!
// 即使我们在这里声明一个被调用,raw: true 将取代并返回一个原始对象。
sequelize
  .query('SELECT * FROM projects', { raw: true })
  .then(projects => {
    console.log(projects)
  })

查询中的替换可以通过两种不同的方式完成:
使用命名参数(以:开头),或者由未命名的

使用的语法取决于传递给函数的替换选项:

  • 如果一个数组被传递,? 将按照它们在数组中出现的顺序被替换
  • 如果传递一个对象,:key将被该对象的键替换。如果包含在查询中的对象未找到对应的键,则会抛出异常,反之亦然。
sequelize
  .query(
    'SELECT * FROM projects WHERE status = ?',
    { raw: true, replacements: ['active']
  )
  .then(projects => {
    console.log(projects)
  })

sequelize
  .query(
    'SELECT * FROM projects WHERE status = :status ',
    { raw: true, replacements: { status: 'active' } }
  )
  .then(projects => {
    console.log(projects)
  })

注意一点: 如果表的属性名称包含 " . ",则生成的对象将被嵌套:

sequelize.query('select 1 as `foo.bar.baz`').then(rows => {
  console.log(JSON.stringify(rows))

  /*
    [{
      "foo": {
        "bar": {
          "baz": 1
        }
      }
    }]
  */
})

如果这篇文章对您有帮助, 感谢 下方点赞 或 Star GitHub: sequelize-docs-Zh-CN 支持, 谢谢.

查看原文

认证与成就

  • 获得 311 次点赞
  • 获得 14 枚徽章 获得 1 枚金徽章, 获得 3 枚银徽章, 获得 10 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2015-09-11
个人主页被 1.7k 人浏览