做个前端,来点 Nginx - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
famanoder
V2EX    Node.js

做个前端,来点 Nginx

  •  
  •   famanoder 2017-09-03 09:00:44 +08:00 9276 次点击
    这是一个创建于 2961 天前的主题,其中的信息可能已经有所发展或是发生改变。

    自从 Nodejs 火了,前端能做的事、要做的事越来越多了;同时对前端的要求也就越来越高,如果现在还只是停留在浏览器端写页面做交互,估计很难找到(更好的)工作了,Node 中间层、Node 微服务、网关这些可以和业务分离的地方以后可能都是前端的事了; Nodejs 是把锋利的瑞士军刀,但你也不要想多了;合理的选型,各司其职,职尽其能,才能发挥各自最大的作用;毕竟一切从实际出发,实事求是,理论联系实际才是最佳的方法论;比如 Nodejs 可以做反向代理( http-proxy ),可以很快的搭建静态资源站,但这些并不是 Nodejs 最擅长的,这些交给 Nginx 显然是个更好的选择,既可以把这些事做更好,还给 Nodejs 服务减压了!

    一、快速拾起 Nginx

    Nginx 是一个高性能的 Web 和反向代理服务器,稳定、强大、系统资源占用低,这些就不说了;

    在 nginx.conf 这个配置文件里,一个 server {}块可以对应一个站点的服务,每个 server {}块里可以配置多个 location {}块来对站点进行路由级别的控制,既可以通过 proxy_pass target 设置反向代理的 server,也可以直接通过 root dir 来访问目录下的静态文件; server_name 设置访问的域,多个用空格隔开,或者用通配符和正则; location 后面可以是正则以及 nginx 提供的丰富的匹配符和变量;记住大括号前面的空格不能省,每行结束语句的分号不能省;

    a. 比如用 Nodejs 启动了一个站点监听 3000 端口,用 a.famanoder.cn 来访问

    server { listen 80; server_name a.famanoder.cn; location / { proxy_pass http://localhost:3000; } } 

    b. 比如把所有的静态资源放到了 dist 目录,用 cdn.famanoder.cn 来访问

    server { listen 80; server_name cdn.famanoder.cn; location / { index index.html; root D:\sources\dist; } } 

    c. 用 vue 做的一个移动端的项目,用 m.famanoder.cn 来访问,所有数据接口由 famanoder.cn 提供;

    server { listen 80; server_name m.famanoder.cn; location /api { # 代理 api,以免跨域 proxy_pass https://famanoder.cn; } location / { index index.html; root D:/vue/dist; } } 

    以上只是最简单的站点和反向代理设置,通过匹配符和正则可以做更多的控制; 二、常用匹配符和变量

    = 等于,严格匹配 != 不等于 ~ 区分大小写匹配 !~ 区分大小写不匹配 ~* 不区分大小写匹配 !~* 不区分大小写不匹配 * 任意字符 -f 和!-f 判断是否存在文件 -d 和!-d 判断是否存在目录 -e 和!-e 判断是否存在文件或目录 -x 和!-x 判断文件是否可执行 

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

    Nginx 里有 if 指令,但是没有 else 指令和&&判断,但可以通过 set 变通的实现: 比如限制 GET 请求参数中的 SQL 关键词:

    set $invalidQuery 1; if( $request_method = GET ){ set $invalidQuery '${invalidQuery}1'; } if( $query_string ~* "select|union|exec" ){ set $invalidQuery '${invalidQuery}1'; } if( $invalidQuery = '111' ){ return 403; } 

    常用变量:

    $args: 请求行中的参数,同$query_string。等于 js 中的 location.search.slice(1)。 $content_type: 请求头中的 Content-Type 字段。 $document_root: 当前请求在 root 指令中指定的值。 $host: 请求主机头字段,否则为服务器名称。等于 js 中的 location.host。 $http_user_agent: 客户端 agent 信息。等于 js 中的 navigator.userAgent。 $http_cookie: 客户端 cookie 信息。等于 js 中的 document.cookie。 $limit_rate: 这个变量可以限制连接速率。 $request_method: 客户端请求的动作,通常为 GET 或 POST。 $remote_addr: 客户端的 IP 地址。 $remote_port: 客户端的端口。等于 js 中的 location.port。 $http_referer:网页来源。等于 js 中的 document.referer。 $remote_user: 已经经过 Auth Basic Module 验证的用户名。 $request_filename: 当前请求的文件路径,由 root 或 alias 指令与 URI 请求生成。 $scheme:HTTP 方法(如 http,https )。等于 js 中的 location.protocol。 $server_protocol: 请求使用的协议,通常是 HTTP/1.0 或 HTTP/1.1。 $server_addr: 服务器地址,在完成一次系统调用后可以确定这个值。 $server_name: 服务器名称。 $server_port: 请求到达服务器的端口号。 $request_uri: 包含请求参数的原始 URI,不包含主机名,等于 js 中的 location.pathname+location.search。 $uri: 不带请求参数的当前 URI,$uri 不包含主机名,等于 js 中的 location.pathname。 $document_uri: 与$uri 相同。 

    三、常见设置:

    1、worker_processes 4 # 开启多进程,一般为 cpu 核数,等于 Nodejs 中的 require('os').cpus().length

    2、error_log logs/error.log info; # log 文件的地址和级别( debug, info, notice, warn, error, crit )

    3、log_format 格式名称 具体格式 # 定义日志内容的格式可以包含$remote_addr $status $http_user_agent 等参数

    4、开启 gzip

    gzip on; gzip_proxied any; gzip_min_length 1024; gzip_buffers 4 8k; gzip_types text/css application/Javascript application/atom+xml application/rss+xml text/plain image/svg+xml application/json text/Javascript; 

    默认的配置文件中只有 gzip on 作用不大,需要自行配置后续 gzip 字段;给所有需要开启 gzip 的资源添加 mimeType,图片不需要 gzip (没有明显效果,体积还可能增大),白白损耗性能;

    四、解决前端跨域问题

    在前后端分离的时候,前后端搭建了两套环境,前端请求数据的时候会跨域,一般是用 Nodejs 做中转,比如使用 http-proxy 和 request 模块,或者在 webpack 的 dev-server 里配置 proxy,浏览器兼容性比较理想的情况下还可以直接设置 CORS ;这样对于打包上线也不需要做太多改动;当然有时候还需要 jsonp ;

    a. 设置 CORS

    server { listen 80; server_name cdn.famanoder.cn; location / { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; index index.html; root D:/sources/dist; } } 

    如果不想设置星号的话,这个变通的做法貌似更灵活,还可以通过跨域反过来限制某些资源的是否可访问

    if ($http_referer ~* 'famanoder.cn') { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; } 

    b. 做 api 中转

    server { listen 80; server_name m.famanoder.cn; location /api { proxy_pass https://localhost:3000; } } 

    五、从 http 切换到 https

    对于一般的散户来说,Letsencrypt 是个不错的选择,可以免费为多个域名提供一套证书(散户福利! Nodejs 多站点切换 Htpps 协议);可以新建一个站点专门为申请证书服务,以免以后重新申请时重启应用或再次搭建;对于切换到 https,只需在 80 端口上直接对指定域名做 301 跳转到 https 对应地址,server 块内做很小改动即可:

    server { listen 80; server_name *.famanoder.com famanoder.com; location / { # 迁移到 https return 301 https://$host$request_uri; } location ~* 'acme-challenge' { # 2333 端口留做以后申请证书用 proxy_pass http://localhost:2333; } } server { # 监听 443 端口,开启 ssl listen 443 ssl; server_name cdn.famanoder.cn; # 把申请到的证书加进来 ssl_certificate D:/crt.pem; ssl_certificate_key D:/key.pem; location / { index index.html; root D:\sources\dist; } } 

    六、Nginx 真的超级强大,而且配置起来并不繁琐,常常简单的设置就可以达到非常强大的功能,比如做安全访问限制、负载均衡等;

    如果你很喜欢一个东西,那么是否应该拿它来做更多有意义的事情!如果你很喜欢 JS,那么是否应该拿它来做更多有意义的事情!那么好的,听说新版 Nginx 开始支持 js 语法了!如果你已在路上,就勇敢的向前吧!

    原文来自:花满楼( https://famanoder.com

    24 条回复    2017-10-24 11:06:48 +08:00
    a1044634486
        1
    a1044634486  
       2017-09-03 10:42:10 +08:00
    我感觉楼主挺厉害的,会前端还会搞 nginx。。
    29EtwXn6t5wgM3fD
        2
    29EtwXn6t5wgM3fD  
       2017-09-03 10:51:38 +08:00
    觉得 Caddy 更简单点
    ychongsaytc
        3
    ychongsaytc  
       2017-09-03 11:32:51 +08:00
    `server_name *.famanoder.com famanoder.com;`

    可以缩写为

    `server_name .famanoder.com;`

    参考 http://nginx.org/en/docs/http/server_names.html
    assad
        4
    assad  
       2017-09-03 11:34:00 +08:00 via Android
    好好写你的前端,非要凑活后端的事
    deleteDB
        5
    deleteDB  
       2017-09-03 12:13:30 +08:00
    战略马克一下
    v1024
        6
    v1024  
       2017-09-03 12:48:17 +08:00 via iPhone
    你说这些是运维的事,这样就是全栈范畴,只不过是从前端转过来的而已。
    webster
        7
    webster  
       2017-09-03 12:52:29 +08:00
    nginx 很简单吧 作为一个前端从 0.8.x 的时候就开始会了 只是现在配置越来越多没时间看文档
    xfspace
        8
    xfspace  
       2017-09-03 12:55:09 +08:00 via Android
    把 SSL 证书链补全下?



    描述:</b>花满楼的小站,一个小前端业余的自娱自乐;自打步入前端,从最初的 html 到 HTML5,从最初的 css 到 CSS3,从最初的 ES3 到 ES6,从最初的 Javascript 到 Nodejs,一路走来,浪迹前端&nbsp;<span id="y"></span>&nbsp;载有余,说实话,除了颜值,没什么拿的出手的了,仅以此记录年轻的追逐和前进的脚步!
    hcymk2
        9
    hcymk2  
       2017-09-03 13:00:03 +08:00
    jswh
        10
    jswh  
       2017-09-03 13:53:05 +08:00
    node 是一把瑞士军刀。但是,瑞士军刀的问题,就是,太小了......。砍树还是要用斧子,打猎还是要用猎枪,甚至杀人还是要用匕首。
    famanoder
        11
    famanoder  
    OP
       2017-09-03 17:13:18 +08:00
    @ychongsaytc 是的
    famanoder
        12
    famanoder  
    OP
       2017-09-03 17:13:51 +08:00
    @assad O(∩_∩)O 哈哈~
    famanoder
        13
    famanoder  
    OP
       2017-09-03 17:15:07 +08:00
    @xfspace 就是一个文件地址,我故意不补全的
    famanoder
        14
    famanoder  
    OP
       2017-09-03 17:15:34 +08:00
    @jswh 对,其实我就是这个意思
    zuolan
        15
    zuolan  
       2017-09-03 17:28:16 +08:00
    啊,原来我有个误区,我一直觉得 Nginx 这种 Web Server 是前端的必备技能,毕竟前端性能优化不能少了 Web Server 的调优,但是看到楼上的回复,emmmm....是我理解错了吗?
    famanoder
        16
    famanoder  
    OP
       2017-09-03 17:41:29 +08:00
    @zuolan 如果工作专职做前端的话,几乎接触不到 nginx 吧?除了自己本地搭建开发环境调试用
    dikT
        17
    dikT  
       2017-09-04 08:53:53 +08:00
    windows server? doge
    zhailei2011
        18
    zhailei2011  
       2017-09-04 09:33:04 +08:00
    Mark
    del1214
        19
    del1214  
       2017-09-04 10:50:03 +08:00
    mark
    sm0king
        20
    sm0king  
       2017-09-04 11:45:37 +08:00
    @assad
    @famanoder

    好可怜,我们公司后端 nginx 貌似不熟悉,每次都是我将 nginx 配置好给他们。每次 nginx 出问题了也是我处理。
    dxcqcv
        21
    dxcqcv  
       2017-09-12 12:55:05 +08:00
    问个问题,

    环境公司内网 redhat 6.0
    应用 node koa,跑在 ip:3000 端口
    想要实现,不加端口号访问,比如直接 ip 地址访问

    现在的问题,无法实现代理,输入 IP 只给我 nginx 的测试页面

    nginx 配置写在自建目录 sites-available/下,名字为 tutorial

    内容为

    ```
    server {
    listen 80;
    server_name 10.xx.xx.xxx;
    location / {
    proxy_pass 10.xx.xx.xxx:3000;
    }
    }
    ```

    快捷方式 ln 到 sites-enabled/目录下
    添加 include 到 nginx.conf 的 http 字段内

    ```
    include /etc/nginx/sites-enabled/*
    ```

    求 LZ 指点一下,哪里错了? nginx -v 1.0.15
    dxcqcv
        22
    dxcqcv  
       2017-09-12 13:38:28 +08:00
    我多方搜索,发现是不是 server_name 不能直接用 ip,一定要用域名?那么在公司内网的服务器中,只有 ip,是否还能用 nginx 来代理呢?
    haierspi
        23
    haierspi  
       2017-10-23 16:54:29 +08:00
    @sm0king 你们公司运维 真是可以滚蛋回家了...头一次听说 线上服务器 允许一个写前端的同事登陆到服务器上操作服务器... 天啊.. 这在我们这... 就是重大事故..
    sm0king
        24
    sm0king  
       2017-10-24 11:06:48 +08:00
    @haierspi 不是啊,我们不允许上去操作服务器的,我们会把我们对 nginx 的需求,给他们写好,发给他们,他们上线,然后出问题后,他们会给我们看日志,这个算是术业专攻吧,我们看日志可以更快更准确的查到问题所在。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1065 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 17:59 PVG 01:59 LAX 10:59 JFK 13:59
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86