Nginx配置与前端集成,求Nodejs相关指导

发布于 1周前 作者 sinazl 来自 nodejs/Nestjs

Nginx配置与前端集成,求Nodejs相关指导

自从 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


25 回复

我感觉楼主挺厉害的,会前端还会搞 nginx。。


觉得 Caddy 更简单点

server_name *.famanoder.com <a target="_blank" href="http://famanoder.com" rel="nofollow noopener">famanoder.com</a>;

可以缩写为

server_name .famanoder.com;

参考 http://nginx.org/en/docs/http/server_names.html

好好写你的前端,非要凑活后端的事

战略马克一下

你说这些是运维的事,这样就是全栈范畴,只不过是从前端转过来的而已。

nginx 很简单吧 作为一个前端从 0.8.x 的时候就开始会了 只是现在配置越来越多没时间看文档

把 SSL 证书链补全下?



描述:</b>花满楼的小站,一个小前端业余的自娱自乐;自打步入前端,从最初的 html 到 HTML5,从最初的 css 到 CSS3,从最初的 ES3 到 ES6,从最初的 JavaScript 到 Nodejs,一路走来,浪迹前端&nbsp;<span id=“y”></span>&nbsp;载有余,说实话,除了颜值,没什么拿的出手的了,仅以此记录年轻的追逐和前进的脚步!

node 是一把瑞士军刀。但是,瑞士军刀的问题,就是,太小了…。砍树还是要用斧子,打猎还是要用猎枪,甚至杀人还是要用匕首。

O(∩_∩)O 哈哈~

就是一个文件地址,我故意不补全的

对,其实我就是这个意思

啊,原来我有个误区,我一直觉得 Nginx 这种 Web Server 是前端的必备技能,毕竟前端性能优化不能少了 Web Server 的调优,但是看到楼上的回复,emmmm…是我理解错了吗?

如果工作专职做前端的话,几乎接触不到 nginx 吧?除了自己本地搭建开发环境调试用

windows server? doge




好可怜,我们公司后端 nginx 貌似不熟悉,每次都是我将 nginx 配置好给他们。每次 nginx 出问题了也是我处理。

问个问题,

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

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

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

内容为

<br>server {<br> listen 80;<br> server_name <a target="_blank" href="http://10.xx.xx.xxx" rel="nofollow noopener">10.xx.xx.xxx</a>;<br> location / {<br> proxy_pass <a target="_blank" href="http://10.xx.xx.xxx:3000" rel="nofollow noopener">10.xx.xx.xxx:3000</a>;<br> }<br>}<br>

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

<br> include /etc/nginx/sites-enabled/*<br>

求 LZ 指点一下,哪里错了? nginx -v 1.0.15

我多方搜索,发现是不是 server_name 不能直接用 ip,一定要用域名?那么在公司内网的服务器中,只有 ip,是否还能用 nginx 来代理呢?

你们公司运维 真是可以滚蛋回家了…头一次听说 线上服务器 允许一个写前端的同事登陆到服务器上操作服务器… 天啊… 这在我们这… 就是重大事故…

不是啊,我们不允许上去操作服务器的,我们会把我们对 nginx 的需求,给他们写好,发给他们,他们上线,然后出问题后,他们会给我们看日志,这个算是术业专攻吧,我们看日志可以更快更准确的查到问题所在。

关于Nginx配置与前端集成,并涉及Node.js的相关指导,以下是一个简要说明及示例配置:

Nginx与Node.js集成概述

Nginx作为一个高性能的Web服务器和反向代理服务器,适合处理静态资源(如图片、CSS、JavaScript文件),而Node.js则基于事件驱动,适合构建高并发、实时的网络应用,适合处理动态请求。将Nginx与Node.js集成,可以发挥各自优势,提升Web应用的性能。

Nginx配置示例

以下是一个Nginx配置示例,展示了如何将静态资源请求和动态请求分别处理:

server {
    listen 80;
    server_name example.com;

    # 处理静态文件
    location /static/ {
        root /var/www/html;
    }

    # 转发API请求到Node.js应用
    location /api/ {
        proxy_pass http://localhost:3000;
        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;
    }
}

Node.js部署建议

  • Node.js应用通常部署在特定端口上(如上述示例中的3000端口)。
  • 为保证Node.js在生产环境中高效稳定运行,建议将其部署在后台并使用进程管理工具(如PM2)来管理。

通过以上配置与部署建议,可以实现Nginx与Node.js的有效集成,从而提升Web应用的综合性能。

回到顶部