4

同源策略引发的跨域问题它都能轻松解决!先来认识认识有这么强大功能框架的神奇之处

 3 years ago
source link: https://xie.infoq.cn/article/518daac0c7681807af02ec58c?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

同源策略引发的跨域问题它都能轻松解决!先来认识认识有这么强大功能框架的神奇之处

发布于: 2021 年 05 月 21 日
同源策略引发的跨域问题它都能轻松解决!先来认识认识有这么强大功能框架的神奇之处

Nginx 概念

  • Nginx 是一款高性能的 HTTP 服务器,反向代理服务器及电子邮件(IMAP/POPP3)代理服务器.由俄罗斯的 Igor Sysoev 所开发,Nginx 能够支撑 5 万并发链接,并且 CPU,内存等资源消耗非常低,运行非常稳定

Nginx 应用场景

  • HTTP 服务器,虚拟主机: Nginx 是一个 HTTP 服务可以独立提供 HTTP 服务,可以做网页静态服务器,可以实现在一台服务器上虚拟出多个网站,例如个人网站使用的虚拟主机

  • 反向代理: 当网站的访问量达到一定程度后,单台服务器不能满足用户请求时,需要用多台服务器集群时可以使用 Nginx 做反向代理

  • 负载均衡: 多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况

HTTP 服务器,虚拟主机

  • 使用 Docker 安装运行 Nginx,在./conf 里创建 nginx.conf 文件,配置 docker-compose.yml

version: '3.1'services:  nginx:  restart: always  image: nginx  container_name: nginx  ports:   - 80:80  volumes:   - ./conf/nginx.conf:/etc/nginx/nginx.conf     - ./wwwroot:/usr/share/nginx/wwwroot
  • 虚拟主机: 虚拟主机是一种特殊的软硬件技术.可以将网络上每一台计算机分成多个虚拟主机,每个虚拟主机可以独立对外提供 www 服务,这样就能实现一台主机对外提供多个 web 服务,每个虚拟主机之间是独立的,互不影响的

  • 通过 Nginx 可以实现虚拟主机的配置,Nginx 支持三种类型的虚拟主机的配置:

  • 基于 IP 的虚拟主机

  • 基于域名的虚拟主机

  • 基于端口的虚拟主机

  • Nginx 配置文件结构: 其中每个 server 就是一个主机

events {}http {  server{  }  server{  }}
基于域名的虚拟主机配置
  • 需求:

  • 两个域名指向同一台 Nginx 服务器,用户访问不同的域名显示不同的网页内容

  • 两个域名是 admin.service.itoken.oxford.com 和 admin.web.itoken.oxford.com

  • Nginx 服务器使用虚拟机 192.168.32.255

  • 配置 Windows Hosts 文件:

  • 修改 window 的 hosts 文件(C:/Windows/System32/drivers/etc)-SwitchHosts

  • 通过 host 文件指定 admin.service.itoken.oxford.com 和 admin.web.itoken.oxford.com 对应 192.168.32.255 虚拟机

  • 创建目录及文件:/usr/local/docker/nginx/wwwroot 目录下创建 htmlservice htmlweb 两个目录,并分别创建 index.html 文件

  • 配置虚拟主机: 修改 /usr/local/docker/nginx/conf 目录下的 nginx.conf 配置文件

user nginx;worker_processes 1;events {  worker_connections 1024;}http{  include        mime.type;  default_type  application/octet-stream;  sendfile      on;  keepalive_timeout  65;  server{    listen         80;    server_name  admin.service.itoken.oxford.com    # 所有的请求都是以 / 开始,所有的请求都可以匹配此location    location / {      root  /usr/local/docker/nginx/wwwroot/htmlservice;      # 指定欢迎页面,按从左到右顺序查找      index index.html index.htm;    }   }  server{    listen           80;    server_name    admin.web.itoken.oxford.com    location / {      root /usr/share/nginx/wwwroot/htmlweb;      index index.html index.htm;    }  }  }
基于端口的虚拟主机配置
  • 需求:

  • Nginx 对外提供 80 和 8080 两个端口监听服务

  • 请求 80 端口则请求 html80 目录下的 html

  • 请求 8080 端口则请求 html8080 目录下的 html

  • 创建目录及文件:/usr/local/docker/nginx/wwwroot 目录下创建 html80 html8080 两个目录,并分别创建两个 index.html 文件

  • 配置虚拟主机: 修改 /usr/local/docker/nginx/conf 目录下的 nginx.conf 配置文件

worker_processes 1;events {  worker_connections 1024;}http{  include        mime.type;  default_type  application/octet-stream;  sendfile      on;  keepalive_timeout  65;  # 配置虚拟主机 192.168.32.255  server{    # 监听的IP和端口,配置192.168.32.255:80    listen         80;    # 虚拟主机名称,这里配置IP地址    server_name  192.168.32.255;    # 所有的请求都是以 / 开始,所有的请求都可以匹配此location    location / {      # 使用 root 指令指定虚拟主机目录即网页存放目录      # 例如:访问 http://ip/index.html 将找到 /usr/local/docker/nginx/wwwroot/html80/index.html      # 例如:访问 http://ip/item/index.html 将找到 /usr/local/docker/nginx/wwwroot/html80/item/index.html      root  /usr/share/nginx/wwwroot/html80;      # 指定欢迎页面,按从左到右顺序查找      index index.html index.htm;    }   }  # 配置虚拟主机 192.168.32.255  server{    listen           8080;    server_name    192.168.32.255;    location / {      root /usr/share/nginx/wwwroot/html8080;      index index.html index.htm;    }  }}

Nginx 反向代理

代理服务器

客户端在发送请求时,不会直接发送给目的主机.而是先发给代理服务器,代理服务器接收客户端请求后,再向主机发出,并接收目的主机返回的数据,存放在代理服务器的硬盘中,再发送给客户机

代理服务器作用
  • 提高访问速度: 由于目标主机返回的数据存放在代理服务器的硬盘中,因此下一次客户在访问相同的站点数据时,会直接从代理服务器的硬盘中读取,起到了缓存的作用,尤其对于热门站点能明显提高请求速度

  • 防火墙作用: 由于所有客户机请求都必须通过代理服务器访问远程站点,因此可在代理服务器上设限,过滤掉某些不安全信息

  • 通过代理服务器访问不能访问的目标站点: 互联网上有许多开放的代理服务器,客户机在访问受限时,可通过不受限的代理服务器访问目标站点

架设在客户机和目标主机之间,只用于代理内部网络对 Internet 的连接请求,客户机必须指定代理服务器,并将本来要直接发送到 web 服务器上的 http 请求发送到代理服务器中

反向代理服务器架设在服务器端,通过缓冲经常被请求的页面来缓解服务器的工作量,将客户机请求转发给内部网络上的目标服务器,并将从服务器上得到的结果返回给 Internet 上请求连接的客户端,此时代理服务器与目标主机一起对外表现为一个服务器

反向代理应用
  • 防止外网对内网服务器的恶性攻击

  • 缓存以减少服务器压力

  • 访问安全控制

  • 进行负载均衡,将用户请求分配给多个服务器

Nginx 反向代理 Tomcat
  • 启动 Tomcat 容器: 启动两个 Tomcat 容器,映射端口为 9090 和 9091,配置 docker-compose.yml

version: '3'services: tomcat1:  image: tomcat  container_name: tomcat1  ports:   - 9090:8080 tomcat2:  image: tomcat  container_name: tomcat2  ports:   - 9091:8080
  • 配置 Nginx 反向代理: 修改 /usr/local/docker/nginx/conf 目录下的 nginx.conf 配置文件

user nginx;worker_processes 1;events {  worker_connection  1024;}http {  include        mime.type;  default_type  application/octet-stream;  sendfile       on;  keepalive_timeout  65;  # 配置一个tomcat1代理服务器  upstream tomcat_server1 {     server 192.168.32.255:9090;  }  # 配置一个tomcat2代理服务器  upstream tomcat_server2{     server 192.168.32.255:9091;  }  server {    listen     80;    server_name  admin.service.itoken.oxford.com    # 所有的请求都是以 / 开始,所有的请求都可以匹配此location    location / {      # 域名 admin.service.itoken.oxford.com的请求全部转发到tomcat_server1,即tomcat1服务器上      proxy_pass http://tomcat_server1;      # 欢迎页面,按照从左到右的顺序查找页面      index index.jsp index.html index.htm;    }   }  server{    listen       80;    server_name    admin.web.itoken.oxford.com    location / {      # 域名 admin.web.itoken.oxford.com的请求全部转发到tomcat_server2,即tomcat2服务器上      proxy_pass http://tomcat_server2;      index index.jsp index.html index.htm;    }  }  }

Nginx 负载均衡

  • 负载均衡建立在现有网络结构之上,提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽,增加吞吐量,加强网络数据处理能力,提高网络的灵活性和可用性

  • 负载均衡(Load Balance),分摊到多个操作单元上进行执行,例如 Web 服务器,FTP 服务器,企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务

Nginx 实现负载均衡
  • 需求:

  • nginx 作为负载均衡服务器,用户请求先到达 nginx,再由 nginx 根据负载均衡配置将请求转发到 tomcat 服务器

  • nginx 负载均衡服务器:192.168.32.255:80

  • tomcat 服务器:192.168.32.255:9090

  • Nginx 配置负载均衡: 修改 /usr/local/docker/nginx/conf 下的 nginx.conf 配置文件

user nginx;worker_processes 1;events {  worker_connection  1024;}http {  include        mime.type;  default_type  application/octet-stream;  sendfile       on;  keepalive_timeout  65;  upstream myapp {      server 192.168.32.255:9090 weight=10;      server 192.168.32.255:9091 weight=10;  }  server{    listen      80;    server_name    nginx.oxford.com;    location / {      proxy_pass  http://myapp;      index    index.jsp index.html index.htm;    }  }}

Nginx 解决跨域问题

  • 在浏览器端进行 Ajax 请求时会出现跨域问题

  • 跨域: 浏览器不能执行其它网站的脚本.是由于浏览器的同源策略造成的,是浏览器对 JavaScript 施加的安全限制

  • 同源: 域名,协议,端口均相同

解决跨域问题方式

使用 CORS(跨资源共享)解决跨域问题
  • CORS 是 W3C 标准,全称"跨资源共享"(Cross-origin resource sharing),允许浏览器向跨源服务器发出 XMLHttpRequest 请求,从而克服了 Ajax 只能同源使用的限制

  • CORS 需要浏览器和服务器同时支持

  • 目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10.

  • 整个 CORS 通信过程,都是通过浏览器自动完成,不需要用户参与.对于开发者来说,CORS 通信与同源 Ajax 通信没有差别,代码完全一样.

  • 浏览器一旦发现 Ajax 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加 的请求,但用户不会有感觉

  • 实现 CORS 通信的关键是服务器,只要服务器实现了 CORS 接口,就可以跨域通信

  • 在 header 中设置:Access-Control-Allow-Origin(在服务器请求控制器中的 controller 类标注 @CrossOrigin(value="*") 注解)

使用 JSONP 解决跨域问题
  • JSONP:(JSON with Padding),JSON 的一种"使用模式:,可用于解决主流浏览器的跨域数据访问问题

  • 由于同源策略,一般 server1.example.com 的网页无法与 server2.example.com 的服务器进行访问,而 HTML 的< script>元素是个例外

  • 利用< script>元素这个开放策略,网页可以得到从其它来源动态产生的 JSON 资料,而使用的这种模式就叫 JSONP

  • 用 JSONP 抓到的资料不是 JSON,而是任意的 JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析

  • 需要目标服务器配合一个 callback 函数


  • CORS 与 JSONP 比较:

  • CORS 与 JSON 使用的目的相同,但是比 JSONP 更强大

  • CORS 支持所有类型的 HTTP 请求

  • JSONP 只支持 GET 请求, JSON 的优势在于支持老式浏览器,以及可以向不支持 CORS 的网站请求数据


Nginx 反向代理解决跨域问题

  • 当服务器无法设置 header 或提供 callback 函数时就可以采用 Nginx 反向代理解决跨域问题

Nginx 配置跨域
  • /usr/local/docker/nginx/conf 中的 nginx.conf 里的 location 中增加配置(Get:字体跨域):

add_header Access-Control-Allow-Origin *或域名;add_header Access-Control-Allow-Headers X-Requested-with;add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
  • 配置 /usr/local/docker/nginx/conf 中的 nginx.conf 配置文件(POST:上传文件):

user nginx;worker_processes 1;events {  worker_connection 1024;}http {  include        mime.types;  default_type    application/octet-stream;  sendfile      on;  keepalive_timeout   65;  server {    listen      80;    server_name    upload.myshop.com;    add_header 'Access-Control-Allow-Origin' '*';    add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-with,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';    location / {      proxy_pass  http://192.168.32.255:8888;      if($request_method = 'OPTIONS'){        add_header Access-Control-Allow-Origin *;        add_header Access-Control-Allow-Headers X-Requested-with;        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,PATCH,OPTIONS;        # 解决假请求问题,如果是简单请求则没有这个问题,这里是上传文件,首次请求为OPTIONS方式,实际请求为POST方式        add_header Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-with,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range;        return 200;      }    }  }}
划线
评论
复制
发布于: 2021 年 05 月 21 日阅读数: 11

版权声明: 本文为 InfoQ 作者【攻城狮Chova】的原创文章。

原文链接:【https://xie.infoq.cn/article/518daac0c7681807af02ec58c】。文章转载请联系作者。

用户头像

一位攻城狮的自我修养 2021.04.06 加入

分享技术干货,面试题和攻城狮故事。 你的关注支持是我持续进步的最大动力! https://github.com/ChovaVea


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK