一、自定义全局异常json数据

  • 任何接口都是可能出错,4xx、5xx等
  • 如果业务没有做好统一的错误管理,直接暴露给用户,无疑是看不懂
  • 所以假如后端某个业务出错,Nginx 层也需要进行转换
  • 让前端知道 Http 响应是200,其实是将错误的状态码定向至200,返回了全局兜底数据

nginx 接口返回时间字段 nginx直接返回200_Access

location / {
    proxy_pass http://lbs;
    proxy_redirect default;

    # 存放用户的真实ip
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;  
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  

    proxy_next_upstream error timeout http_503 non_idempotent;
    
    #开启错误拦截配置,一定要开启
    proxy_intercept_errors on;
}

# 不加 =200,则返回的就是原先的http错误码;配上后如果出现500等错误都返回给用户200状态,并跳转至/default_api
error_page  404 500 502 503 504  =200  /default_api;

location = /default_api {
    default_type application/json;
    return 200 '{"code":"-1","msg":"invoke fail, not found "}';
}

nginx 接口返回时间字段 nginx直接返回200_Access_02

二、封禁恶意IP

Nginx 的层面封IP ,方式多种 (但 req 还是会打进来, 让 Nginx 返回 403,占用资源)

nginx 接口返回时间字段 nginx直接返回200_运维_03

单独网站屏蔽IP的方法,把include xxx; 放到网址对应的在 server{} 语句块,虚拟主机
所有网站屏蔽IP的方法,把include xxx; 放到 http{} 语句块。

nginx配置如下:

http{
    # ....
    # blacklist.conf 和 nginx.conf 在同一个目录下
    include blacklist.conf;
}

location / {
    proxy_pass http://lbs;
    proxy_redirect default;
}


# blacklist.conf 文件内容
deny 192.168.159.2;
deny 192.168.159.32;

nginx 接口返回时间字段 nginx直接返回200_nginx_04

自动化封禁思路

  • 编写 shell 脚本
  • AWK 统计 access.log,记录每秒访问超过60次的ip,然后配合 Nginx 或者 iptables 进行封禁
  • crontab 定时跑脚本

三、解决浏览器跨域

跨域:浏览器同源策略。1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。 最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"三个相同"

nginx 接口返回时间字段 nginx直接返回200_nginx_05

协议相同  http https
域名相同  www.xdclass.net
端口相同  80  81

一句话:浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域

浏览器控制台跨域提示:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

nginx 接口返回时间字段 nginx直接返回200_.net_06

解决方法

  • JSONP
  • Http 响应头配置允许跨域
  • Nginx 层配置
  • 程序代码中处理通过拦截器配置

location下配置

nginx 接口返回时间字段 nginx直接返回200_.net_07

location / { 
    add_header 'Access-Control-Allow-Origin' $http_origin;
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
    add_header Access-Control-Allow-Methods 'GET,POST,OPTIONS';

    #如果预检请求则返回成功,不需要转发到后端
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 200;
    }
}

nginx 接口返回时间字段 nginx直接返回200_nginx_08

四、location规则

正则

^ 以什么开始
$ 以什么结束

^/api/user$

语法 location [ = | ~ | ~* | ^~ ] uri { ...... }

nginx 接口返回时间字段 nginx直接返回200_运维_09

location = /uri
= 表示精准匹配,只要完全匹配上才能生效

location /uri
不带任何修饰符,表示前缀匹配

location ^~ /uri/
匹配任何已 /uri/ 开头的任何查询并且停止搜索

location /
通用匹配,任何未匹配到其他location的请求都会匹配到

nginx 接口返回时间字段 nginx直接返回200_.net_10

正则匹配

  • 区分大小写匹配(~)
  • 不区分大小写匹配(~*)

优先级(不要写复杂,容易出问题和遗忘)

  • 精准匹配 > 字符串匹配(若有多个匹配项匹配成功,那么选择匹配长的并记录) > 正则匹配

案例

nginx 接口返回时间字段 nginx直接返回200_运维_11

server { 
  server_name xdclass.net;   
  location ~^/api/pub$ { 
    ...
  }
}

^/api/pub$这个正则表达式表示字符串必须以/开始,以b $结束,中间必须是/api/pub

http://xdclass.net/api/v1 匹配(完全匹配)

http://xdclass.net/API/PUB 不匹配,大小写敏感

http://xdclass.net/api/pub?key1=value1 匹配

http://xdclass.net/api/pub/ 不匹配

http://xdclass.net/api/public 不匹配,不能匹配正则表达式

nginx 接口返回时间字段 nginx直接返回200_nginx 接口返回时间字段_12

测试

nginx 接口返回时间字段 nginx直接返回200_nginx 接口返回时间字段_13

location = /img/test.png {
    1;
}

location /img/test.png {
    return 2;
}

location ^~/img/ {
    return 3;
}

location =/ {
    return 4;
}

location / {
    return 5;
}

nginx 接口返回时间字段 nginx直接返回200_nginx_14

五、rewrite规则应用

rewrite 地址重定向,实现 URL 重定向的重要指令,他根据 regex (正则表达式)来匹配内容跳转到

  • 语法 rewrite regex replacement[flag]
    rewrite ^/(.*) https://xdclass.net/$1 permanent

这是一个正则表达式,匹配完整的域名和后面的路径地址

replacement部分是https://xdclass.net/$1,$1是取自regex部分()里的内容

  • 常用正则表达式:

nginx 接口返回时间字段 nginx直接返回200_.net_15

字符            描述
^               匹配输入字符串的起始位置
$               匹配输入字符串的结束位置
*               匹配前面的字符零次或者多次
+               匹配前面字符串一次或者多次
?               匹配前面字符串的零次或者一次
.               匹配除“\n”之外的所有单个字符
(pattern)       匹配括号内的pattern

nginx 接口返回时间字段 nginx直接返回200_Access_16

  • rewrite 最后一项 flag 参数
    标记符号 说明 last 本条规则匹配完成后继续向下匹配新的location URI规则 break 本条规则匹配完成后终止,不在匹配任何规则 redirect 返回302临时重定向 permanent 返回301永久重定向

应用场景

  • 非法访问跳转,防盗链
  • 网站更换新域名
  • http 跳转 https
  • 不同地址访问同一个虚拟主机的资源

六、配置websocket反向代理

nginx 接口返回时间字段 nginx直接返回200_nginx_17

server {
  listen    80;
  server_name xdclass.net;
  location / {
    proxy_pass http://lbs;
       proxy_read_timeout 300s; //websocket空闲保持时长
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_http_version 1.1;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
  } 
}

nginx 接口返回时间字段 nginx直接返回200_运维_18

核心是下面的配置 其他和普通反向代理没区别, 表示请求服务器升级协议为WebSocket

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

服务器处理完请求后,响应如下报文,状态码为101

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade