目录

  • 前言
  • Nginx 反向代理常用配置
    • Server
    • location
    • proxy_pass
    • add_header
    • OPTIONS 请求
    • proxy_set_header
    • 跨域的 cookie 传输
    • Proxy_cookie_domain
    • WithCredentials
    • Access-Control-Allow-Credentials
    • Proxy_cookie_path
    • 最后

前言

编码两分钟,解决跨域两小时,我吐了。

Nginx 反向代理常用配置

打开 conf/nginx.conf 文件,如果只是做反向代理的话,大部分情况只需要配置 http 模块下的 server 即可,一般初始文件,只有一个 server,如果你需要 Nginx 同时开启不同的端口或域名,就需要写多个 server。

Server

一个 server 模块的配置如下:

server {listen       80;   # 端口号server_name  localhost;   # server name 默认 localhost#access_log  logs/host.access.log  main;location / {   # 访问路径匹配规则root   html;index  index.html index.htm;}error_page   500 502 503 504  /50x.html;  # 错误处理location = /50x.html {root   html;}
}

里面比较重要的是 location 模块,反向代理的主要工作也是配置 location。

location

Location 配置项定义了一条访问 Nginx 服务某一路径时的匹配规则,location 后面紧跟的是匹配的路径,这个路径可以直接写绝对路径,可以写正则匹配:

location /api1 { # 当访问 http://localhost/api1 时命中# ...
}location ~ ^/(api2/api3) { # 当访问 http://localhost/api2 和 http://localhost/api 3 时命中# ...
}

proxy_pass

location 里有多个配置项,其中一个是 proxy_pass ,意思是将当前命中的 Nginx 接口(例如:http://localhost/api )代理到其他 server 的接口,如下例子就是将 http://localhost/api 代理到 https://baidu.com/api

location /api {proxy_pass https://baidu.com;
}

需要注意的是,在写 proxy_pass 不能随便在目标地址后加 /,如果你在地址末尾加了 / ,则最终代理是这样的:

location /api {proxy_pass https://baidu.com/; # 将会被代理到 https://baidu.com/,后面没有 /api
}

不加 /,则最终代理是这样的,访问 Nginx 命中的 /api ,Nginx 也会自动帮你拼接上去:

location /api {proxy_pass https://baidu.com; # 将会代理到 https://baidu.com/api
}

add_header

location 配置中的 add_header选项,表示 Nginx 将在 response 中添加一些额外的响应头信息给客户端。众所周知,开启跨域支持是需要服务端配置 Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers 这些请求头的,那么既然有了Nginx 做了中间层代理服务,就算 server 不给我们开启这些,我们完全也能够自给自足:

location /api {add_header Access-Control-Allow-Origin * always;add_header Access-Control-Allow-Headers *;add_header Access-Control-Allow-Methods "GET, POST, PUT, OPTIONS";proxy_pass https://baidu.com;
}

其中 * 代表通配符,意思是所有 origin 都允许跨域访问,这个当然是不安全的,但是本地开发就无所谓了,你也可以写自己指定的本地服务。

一般来说,如果请求过程中出现 40X 50X的错误,Nginx 将不会设置 Access-Control-Allow-Origin 继而导致跨域失败,所以需要在后面再加个 always 告诉 Nginx 不管怎样,都给我设置这个响应头。

OPTIONS 请求

其实,编写到这里,大多数的跨域场景,我们应该能很好的解决了,但是我的项目所需要解决的跨域问题,还不是这么简单。

首先,在开发的过程中,我发现对于有些 server ,连我发送的 OPTIONS 请求都过不去,查看 Nginx 日志才发现,Nginx 本身确实帮我将 OPTIONS 请求代理出去了,但是服务端不认这个 Request Method,它只认识 POST,反手给我一个 403。这就麻烦了,server 端不认这个请求,那么后续的 POST 根本没法发,这要咋办?

一番思考后,如果我直接让 Nginx 拦截 OPTIONS 直接响应 200 不就可以了嘛?

location /api {add_header Access-Control-Allow-Origin * always;add_header Access-Control-Allow-Headers *;add_header Access-Control-Allow-Methods "GET, POST, PUT, OPTIONS";if ($request_method = 'OPTIONS') {return 200;}proxy_pass https://baidu.com;
}

重启,再试,成功。Nice,第一个问题解决。

proxy_set_header

这个配置项我的项目里并没有怎么用到,但是还是说一下,以便和 add_header 做出区分。

  • add_header 是当请求从 server 端回来时,Nginx 再往这个 response 里添加一些额外的 reponse header 然后发送给 客户端
  • proxy_set_header 是当请求从客户端发出时,Nginx接收到 request 再往请求里添加一些额外的 request header 然后发送给 服务端

常见的一些需要设置 proxy_set_header 的场景,比如说,有些 server 可能需要验证 Host,这个时候,就可以使用 proxy_set_header 伪造一个 Host 来骗过服务端。

跨域的 cookie 传输

cookie 这个东西,由于事关安全性,所以是非常敏感的。Domain 不同,Path 不同,浏览器就不会让你访问到这个 Cookie,也不可能存储这个 Cookie ,更不可能让你随随便便地带着 Cookie 跨域名传输,所以要开启跨域情况下的 Cookie 传输,要求也是十分严苛的。

首先,我碰到的一个场景是:server 端需要记录访问 session ,以此来判定当前用户的登陆状态,后面的所有接口,都需要通过 session 来判断。然而当我成功调通登陆接口后,发现后续的所有接口都 Error 并且直接给我 302 到登陆界面,这就说明在服务端那里,我的状态根本就是没登陆,这是怎么回事?

一通排查,我发现是因为 server 端登陆成功后返回的一系列 session 我并没有做处理,所以它们的 Domain 都是 server 的 Domain。浏览器拿到后一看,你当前域是 localhost,你 Cookie 域是其他的域,cookie 不能给你。而后面的请求没有携带这些 session 信息,服务端自然不认得。

一通操作,终于找到了一个叫做 proxy_cookie_domain 的东西。

Proxy_cookie_domain

这个选项是专门用来修改服务端返回回来的 cookie domain ,可以使用这个配置来将 cookie domain 手动修改后再返回,修改成本地开发的域,这样就能绕过浏览器的限制,成功将 cookie 保存。

location /api {add_header Access-Control-Allow-Origin * always;add_header Access-Control-Allow-Headers *;add_header Access-Control-Allow-Methods "GET, POST, PUT, OPTIONS";if ($request_method = 'OPTIONS') {return 200;}proxy_cookie_domain ~\.?baidu.com $host;proxy_pass https://baidu.com;
}

再试,可以,这把登陆完成后,打开控制台发现所有来自 server 的 cookie 都被保存下来了。接着请求其他接口,失败。

继续找原因,发现是因为就算是本地访问了 Nginx 服务,其实也是跨域的,只不过我将 Nginx 开启了支持普通跨域,可是它不支持 cookie 的跨域传输啊。支持跨域传输 cookie 需要前后端同时支持。

WithCredentials

首先在前端这块,我用的是 axios,里面有一项安全认证的配置需要开启:withCredentials: true。将这个配置项打开,代表请求服务端进行跨域的 cookie 传输。

这个 withCredentials 配置项,应该是业界统一命名,命名差别不大,如果不是用的 axios 而且用的别的插件,应该都有这个配置项,写法不同而已,找一下应该能找到。

Access-Control-Allow-Credentials

搞完前端,继续搞 Nginx 里面需要加一个响应头信息:Access-Control-Allow-Credentials: true,代表服务端同意跨域传输凭证。

location /api {add_header Access-Control-Allow-Origin * always;add_header Access-Control-Allow-Headers *;add_header Access-Control-Allow-Methods "GET, POST, PUT, OPTIONS";add_header Access-Control-Allow-Credentials true;if ($request_method = 'OPTIONS') {return 200;}proxy_cookie_domain ~\.?baidu.com $host;proxy_pass https://baidu.com;
}

再试,失败,我*****

再找原因,发现如果开启了 Access-Control-Allow-Credentials 那么 Access-Control-Allow-Origin 和 Access-Control-Allow-Headers 不能写成 * 这种通配符的形式,必须写明 origin 和 headers。

location /api {add_header Access-Control-Allow-Origin http://localhost:3000 always;add_header Access-Control-Allow-Headers "Accept,Accept-Encoding,Accept-Language,Connection,Content-Length,Content-Type,Host,Origin,Referer,User-Agent";add_header Access-Control-Allow-Methods "GET, POST, PUT, OPTIONS";add_header Access-Control-Allow-Credentials true;if ($request_method = 'OPTIONS') {return 200;}proxy_cookie_domain ~\.?baidu.com $host;proxy_pass https://baidu.com;
}

重启 Nginx,再试,成功了。

Proxy_cookie_path

在解决问题的过程中,我发现还有个叫做 proxy_cookie_path 的配置,虽然我没用到,但还是记录一下,这个配置的作用看名字就知道,应该和 proxy_cookie_domain 类似。
一般情况下,server 返回的 cookie 里,可能会写有 Path,如果浏览器的当前 Path 不满足这个 cookie path 的限定条件,cookie 同样是不可操作的。这个 proxy_cookie_path 配置就是为了将 server 返回的 cookie path 改写成自己需要的 cookie path 从而绕过浏览器的限制。

最后

给个 Nginx 配置项官方传送:Nginx 配置
和一篇不错的 nginx 的博客:Nginx 使用与异常处理

Nginx 反向代理解决跨域问题相关推荐

  1. 通过nginx反向代理解决跨域

    先写一个发送跨域请求的页面index.html <html> <head><title></title> </head> <body& ...

  2. 利用nginx 反向代理解决跨域问题

    利用nginx 反向代理解决跨域问题 参考文章: (1)利用nginx 反向代理解决跨域问题 (2)https://www.cnblogs.com/hpx2020/p/9928175.html 备忘一 ...

  3. nginx反向代理解决跨域问题,使本地调试更方便

    nginx反向代理解决跨域问题,使本地调试更方便 参考文章: (1)nginx反向代理解决跨域问题,使本地调试更方便 (2)https://www.cnblogs.com/gwf93/p/102951 ...

  4. nginx解决浏览器跨域问题_前端通过Nginx反向代理解决跨域问题

    在前面写的一篇文章SpringMVC解决跨域问题,我们探讨了什么是跨域问题以及SpringMVC怎么解决跨域问题,解决方式主要有如下三种方式: JSONP CORS WebSocket 可是这几种方式 ...

  5. Nginx反向代理解决跨域问题(个人学习总结)

    一.理解Nginx Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行.其特点是占有内存少,并发能力强,事实上nginx的并 ...

  6. 【Nginx反向代理解决跨域】

    跨域 写在前面 当今互联网行业,大部分Web项目基本都是采用的前后端分离模式.前端为H5项目,后端为Java.PHP.Python等项目.而且大部分后端服务并不会只部署一套服务,而是会采用Nginx对 ...

  7. webstorm前端使用Nginx 反向代理解决跨域问题

    1.webstorm设置端口 2. 3. 4. 5. 把项目放到nginx安装目录的html文件夹下: 6. 配置nginx.conf文件 server {listen 8090; #监听端口serv ...

  8. nginx反向代理解决跨域请求问题

    1.出现跨域的表现: 项目的前端调用后台接口时候,会报错: No 'Access-Control-Allow-Origin' header is present on the requested re ...

  9. Nginx 方向代理解决跨域问题-2

    概述 在浏览器端进行 Ajax 请求时会出现跨域问题,那么什么是跨域,如何解决跨域呢?先看浏览器端出现跨域问题的现象,如下图所示 什么是跨域问题? 跨域,指的是浏览器不能执行其他网站的脚本.它是由浏览 ...

最新文章

  1. Tomcat介绍、安装JDK、安装Tomcat
  2. Python 三元条件判断表达式(and or/if else)
  3. 关于/etc/fstab
  4. C++11语言新特性-《C++标准库(第二版)》读书笔记
  5. 算法漫画:什么是 “哈夫曼树” ?
  6. C++获取PE文件的入口点
  7. SVN学习总结(4)——解决Win10 SVN图标不显示问题
  8. BZOJ2957楼房重建
  9. 第三百九十一节,Django+Xadmin打造上线标准的在线教育平台—404,403,500页面配置...
  10. 【技巧】LeetCode 86. Partition List
  11. UGUI的Button和Toggle
  12. php socket端口监听端口号,swoole websocket服务器中添加监听tcp的端口
  13. 节奏大师服务器不稳定,节奏大师无法登陆的原因及解决方法
  14. OpenGL 渲染 YUYV(YUV422)
  15. 使用135编辑器HTML样式,135编辑器滑动样式全教程!
  16. Windows11安装WSA教程android子系统安装方法(22000+dev) Msixbundle(1.2GB) 安装包下载
  17. What is a computer?
  18. shell美元符_Linux Shell中的美元符号$ | 学步园
  19. mysql 合计 小计_用SQL实现统计报表中的小计与合计的方法详解
  20. 儿童用灯哪个品牌好?推荐专业的儿童护眼台灯

热门文章

  1. vscode输入vue自动_使用vscode,新建.vue文件,tab自动生成vue代码模板
  2. c语言中有死循环时上机编译,2011级C语言复习题(精简)
  3. 网络教育统考计算机怎么考试,网络教育统考怎么考
  4. 2021.08.28-MMsegmentation0.16.0+Cuda10.1+Ubuntu16.04+Pytorch1.8环境安装
  5. AngularJS-模型和控制器
  6. mysql中的视图_分布式 | DBLE 是如何实现视图的?
  7. python网络框架生产环境_配置Django框架为生产环境的注意事项(DEBUG=False)
  8. 端口映射 - 专业术语 - 发问篇
  9. H5调用手机摄像头拍照,如何压缩后上传
  10. CorePress-v4.5网站主题 WordPress主题