nginx 跨域问题

一. 什么是同源策略

一点历史:

Netscape Communications Corporation(最初是 Mosaic Communications Corporation)网景是一家独立的美国计算机服务公司,总部位于加利福尼亚州的山景城,然后在弗吉尼亚州的杜勒斯。[ 2] 它的Netscape Web浏览器曾经一度占主导地位,但在所谓的 第一次浏览器大战之后输给了Internet Explorer和其他竞争者,其市场份额从1990年代中期的90%以上下降到2002年的不足1%。 2006. Netscape创建了 JavaScript编程语言,这是用于客户端网页脚本的最广泛使用的语言。该公司还开发了SSL,用于在其后继 TLS接管之前保护在线通信的安全。
Netscape Navigator 2.0 是网景公司的旗舰产品,是第一个支持 JavaScript 和  gif 动画的浏览器。
在1995年 Netscape Navigator 2.02版本中引入了同源策略的概念,目前,所有浏览器都实行这个策略。。

同源策略

在计算中,同源策略(有时缩写为SOP)是Web应用程序安全模型中的重要概念。可见同源策略是为了 Web 的安全出现的产物。

根据该策略,Web浏览器只允许第一个网页中包含的脚本(JS)访问第二个网页中的数据时,两个网页具有相同的来源

何为相同的来源,两个网页的:
  • 协议(http/https)相同
  • 域名(IP)相同
  • 端口 相同

举例来说 假设要某一台服务器提供的一个资源,这个资源的 url 是 http://www.sharkyun.com/api/json

协议是: http:// 域名是: www.sharkyun.com 端口是: 80(默认端口可不写)

那从如下url 的网页访问 http://www.sharkyun.com/api/json 时的情况如下

http://www.sharkyun.com/user/:同源
http://sharkyun.com/dir/other.html:不同源(域名不同)
http://www.testedu.com/topic/linux/:不同源(域名不同)
https://www.sharkyun.com/dir/other.html:不同源(协议不同)
http://www.sharkyun.com:81/dir/other.html:不同源(端口不同)

浏览器遵循同源策略的目的

同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。

此策略可防止一个页面上的恶意脚本(JavaScript 语言编写的脚本程序)通过该页面的文档对象模型来访问另一网页上的敏感数据。

 

由此可见,同源政策是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。

请记住,同源策略仅适用于 JavaScript 脚本,这一点非常重要。

换句话说,同源策略不适用于 HTML 标签,比如:

<img src="">
   <link rel="stylesheet" type="text/css" href="">
   <script type="text/javascript"></script>
   <iframe src=""></iframe>

这意味着可以一个网站可以通过网页上相应的HTML标签进行跨源访问另外一个网站的诸如图片,CSS和 JS之类的静态资源。

同源策略的限制范围

  • Cookie、LocalStorage 和 IndexDB 无法读取。
  • Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享
  • DOM 无法获得。
  • 如果两个网页不同源,就无法拿到对方的DOM。典型的例子是iframe窗口和window.open方法打开的窗口,它们与父窗口无法通信
  • AJAX 请求不能发送。
  • 同源政策规定,AJAX请求只能发给同源的网址,否则就报错。
    No 'Access-Control-Allow-Origin' header is present on the requested resource.

接下来,只讨论 AJAX 请求的跨域问题(见下文)。

二、跨域

1 什么是跨域

当从 A 网站的网页代码中 请求访问 B 网站中的数据资源的行为就成为跨域。

3 为何会产生跨域

目前主流的架设网站的技术都是采用前后端分离。

前端只负责静态资源的提供,提供此资源的服务器也称为前端服务器

后端只负责动态资源的提供,提供此资源的服务器也称为后端服务器

静态资源包含 html 页面,css 文件,js 文件, 图片等

动态资源就是 数据库中的纯数据。

比如用户的购物车中的商品,或者电商提供的产品的库存数据等。

一个完成的页面需要静态资源和动态资源的组合。

 

通常前端服务器会通过自己静态页面中的 JS 代码向后端服务器请求数据,

之后把请求到的数据,填充到自己的静态页面中,这个过程也可称为渲染。

在次过程中就会产生跨域的行为。

3.1 部署实验环境

192.168.1.37 Centos7 /Docker nginx 前端服务器

192.168.1.38 Centos7 nginx uwsgi 后端服务器

​ (同时具备反向代理功能)

部署 Nginx 不在讨论,相信既然了解跨域的知识了,部署 Nginx 应该不是问题。

下面只说一下每个服务器的配置文件和页面内容

  • 两台 Nginx 的主配置文件 /etc/nginx/nginx.conf 都一致
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
  • 192.168.1.37 的子配置文件 /etc/nginx/conf.d/default.conf

基本按照默认的即可

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
  • 192.168.1.37 添加如下内容到 /usr/share/nginx/html/index.html 文件中,作为网站的首页内容。
<!DOCTYPE html>          
<title> 欢迎来到 shark yun</title>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"></script>

 

 

<!-- img 标签直接跨域访问静态资源-->
 <img src="http://192.168.1.38/qfnz.jpg">

// AJAX 跨域请求 $.ajax({ url: 'http://192.168.1.38/api/json', type: 'GET', dataType: 'json', success: function(res){ // 转换为字符串 data=JSON.stringify(res)</p> <pre><code> // 添加数据到 页面的 div 标签中 $("#json").text(data); }, error: function(res){ console.error(res); } }); </code></pre> <p> ```

  • 192.168.1.38 的子配置文件 /etc/nginx/conf.d/default.conf
server {
    listen       80;
    server_name  localhost;

    location / {
         include uwsgi_params;
         uwsgi_pass 127.0.0.1:8000;
    }

    location ~* \.(gif|jpg|jpeg|js)$ {
        root /static;  # 需要创建对应的目录
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
  • 在 192.168.1.38 服务上创建静态资源存放的目录

mkdir /static # 注意和上面配置文件中的一致

  • 传输示例图片到 192.168.1.38 服务器的 /static 目录中, 并命名为 qfnz.jpg

 

3.1.1 uwsgi 介绍

uwsgi 可以启动一个提供动态资源的服务器,有相应的监听端口,支持 socket 和 http 形式。

目前支持多种编程语言,这里我们使用 python。

我们之前说动态资源的数据是存放在数据库中的,编程语言可以访问数据库。但是这里不会真的去连接数据库,这里会用假数据代替。不影响理解跨域。

3.1.2 部署 uwsgi

Uwsgi 官方文档

  • 在 192.168.1.38 服务器上执行如下操作

安装依赖软件

yum install epel-release python2-devel python2-pip

使用 pip 安装 uwsgi

pip install uwsgi

创建应用程序目录

mkdir /opt/webapp

进入应用程序目录并创建 应用程序文件 app.py , 添加如下内容

[root@localhost webapp]# cat /opt/webapp/app.py
headers=('Content-Type', 'application/json;charset=utf-8')

def application(env, start_response):
    if env['PATH_INFO'] == '/api/json':
        start_response('200 OK', [headers])
        data = '{"name": "shark", "age": 18}'
        return [data]

继续在应用程序目录创建 uwsgi 的配置文件 qf-uwsgi.ini, 添加如下内容

[root@localhost webapp]# cat /opt/webapp/qf-uwsgi.ini
[uwsgi]
# 监听本地端口 8000
socket = 0.0.0.0:8000

# 进入到应用程序(app)的主目录
chdir = /opt/webapp/

# 指定app 的启动文件
wsgi-file = app.py

#开启 4 个进程
processes = 4

# 每个进程开启 2 个线程
threads = 2

3.2 启动服务

3.2.1 启动 uwsgi

后端服务器上执行

cd /opt/webapp
# 启动 uwsgi
nohup uwsgi qf-uwsgi.ini &

# 启动 nginx
systemctl start nginx

# 检查监听端口
ss -ntal  |grep 80

 

继续在 前端服务器上启动 nginx 服务

systemctl restart nginx

4 解决 AJAX 跨域请求

解决跨域的方法很多,这里仅介绍 Nginx 方式。

接下来会已以实际例子来模拟由于跨域访问导致的浏览器报错,之后通过在 Nginx 代理服务器上设置相应的参数来解决跨域。

从而让运维人员搞清楚什么是宽域,运维人员如何在服务端解决跨域。

先来说说解决 AJAX 跨域的解决方法

  • JSONP
  • WebSocket
  • CORS

4.1 JSONP

是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。是最早解决的方法,目前已不常用。

4.2 WebSocket

WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。 也不常用。

4.3 CORS

CORS 是跨源资源共享(Cross-Origin Resource Sharing)的缩写。

它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求。

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

整个CORS通信过程,都是浏览器自动完成,不需要使用浏览器的用户参与。

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

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

4.4 两种请求

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

  • 只要同时满足以下两大条件,就属于简单请求。否则就是非简单请求。
  1. 请求方法是以下三种方法之一:
  2. HEAD
  3. GET
  4. POST
  5. HTTP的头信息不超出以下几种字段:
  6. Accept
  7. Accept-Language
  8. Content-Language
  9. Last-Event-ID
  10. Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

浏览器对这两种请求的处理,是不一样的。

下面仅分析简单请求

4.5 简单请求

对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。

目前可以在任意一个浏览器中输入 http://192.168.1.37

 

 

之后右键 点击 检查

 

在浏览器下方 点击 Network

 

 

再次刷新 浏览器, 并点击 json


这个 json 资源的请求就是第一次访问 前端服务器时返回的首页中的 JS 代码发送的一次跨域请求。

 

再次点击 Network

并在 右侧窗口的底部 会看到 Request Headers (请求头)

 

会发现 在请求头中有一字段 Origin

 

这个字段的值表明的此次请求是从那发出来的,就是说明这次请求的源是哪儿:协议 + 域名 + 端口

可以看到图片中的源是 :http://192.168.1.37

这个地址正式我们这个页面的服务器地址。

但是此次请求的目标并不是 http://192.168.1.37 而是 192.168.1.38

可以从这个窗口的最上方内容中看到

 

从下图信息中可以看的出来,

这次请求的资源 json 的 url 为:http://192.168.1.38/api/json

域名是192.168.1.38

但是请求头中的 Origin 字段的值是 192.168.1.37

这就是跨源(跨域)访问

 

前面说了, CORS需要浏览器和服务器同时支持。

服务器接收到请求,从请求头中会拿到这个 Origin 的值。

服务器可以根据自己的配置,来确定是否要返回此次请求的数据。

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应,此时的响应码可能是 200。也就是不可以从响应的状态码来判断跨域请求是否成功。

 

 

当浏览器接收到服务器的响应信息,查看响应头。

会发现,这个响应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequestonerror回调函数捕获。

 

报错信息如下

 

总结: 浏览器 CORS 跨源请求是否被允许,浏览器判断的是服务器响应头中是否含有 Access-Control-Allow-Origin字段。

4.6 解决简单请求的跨源访问

从上面的总结中可以看出,服务端解决跨域问题的最简单的方法是在服务器的响应头中添加 Access-Control-Allow-Origin 字段。

此时我们可以在后端服务器(192.168.1.38) 中的配置文件default.conf添加如下内容 :

add_header Access-Control-Allow-Origin *;

允许任何源发送请求
add_header Access-Control-Allow-Origin *; 
也可以指定具体的一个源
add_header Access-Control-Allow-Origin  http://192.168.1.37
server {
    listen       80;
    server_name  localhost;

    # 添加响应头信息
    add_header Access-Control-Allow-Origin *;
    location / {
         include uwsgi_params;
         uwsgi_pass 127.0.0.1:8000;
    }

    location ~* \.(gif|jpg|jpeg|js)$ {
        root /static;  # 需要创建对应的目录
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

接下来重启 nginx 服务

systemctl restart nginx

重启成功后,再次刷新网页

会看到响应头信息

 

页面中也会展示处理响应的数据

 

4.7 响应头信息的说明

如果Origin指定的域名在许可范围内,根据服务器端不同的设置,服务器返回的响应,可能会多出几个头信息字段。

http Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8

上面的头信息之中,有三个与CORS请求相关的字段,都以Access-Control-开头。

(1)Access-Control-Allow-Origin

该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

(2)Access-Control-Allow-Credentials

该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。

(3)Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值