跨域问题以及Nginx配置文件

为什么会有跨域问题

同源策略/SOP(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。

SOP要求两个通讯地址的:

  • 协议 (http、https)
  • 域名 (a.com、b.com)
  • 端口号 (a.com:8080、a.com:8000)

必须相同,否则两个地址的通讯将被浏览器视为不安全的,并被block下来

前端跨域问题解决方式:

1.与服务端部署到同域上(正常部署)

正常将web项目放置到服务端项目的静态文件所在目录即可
缺陷:

  • 若服务端与web端并非相同公司或者项目组开发:需要将项目整合,然后交到服务端开发人员或者web端开发人员进行部署,部署人员可能对于另外一端的业务部署导致不必要的矛盾。
  • 若web项目的服务器分属于不同的域:可能需要将web项目拆分成不同的部分分别部署到不同的服务器上,加大了部署的困难程度。

2.CORS

同域安全策略CORS(Cross-Origin Resource Sharing)
它要求请求的服务器在响应的报头(Response Header)添加 Access-Control-Allow-Origin标签,从而允许此标签所对应域访问此服务器的资源,调用此服务器的接口。
缺陷:

  • 默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等),通过将withCredentials属性设置为true,可以指定某个请求应该发送凭据。如果服务器接收带凭据的请求,会用下面的HTTP头部来响应:
Access-Control-Allow-Credentials: true

如果发送的是带凭据的请求,但服务器的相应中没有包含这个头部,那么浏览器就不会把相应交给JavaScript,请求就无法得到结果的数据(浏览器得到了,但是我们请求的方法得不到,因为被浏览器拦截了),因此在需要传Cookie等时,服务端的Access-Control-Allow-Origin必须配置具体的具体的域名。并且还需要设置其他的请求头:

Access-Control-Allow-Origin;  //request.getHeader("Origin")||www.xxx.com
Access-Control-Allow-Methods;  //POST, GET, OPTIONS, DELETE
Access-Control-Allow-Credentials;//是否支持cookie跨域  
Access-Control-Allow-Headers;//x-requested-with,content-type

Java可以参照:

public void CORSMethod(ServletRequest request, ServletResponse response) throws IOException,ServletException {
    HttpServletResponse res = (HttpServletResponse) response;
    res.setContentType("text/html;charset=UTF-8");
       res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    res.setHeader("Access-Control-Max-Age", "0");
       res.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token");
       res.setHeader("Access-Control-Allow-Credentials", "true");
       res.setHeader("XDomainRequestAllowed","1");
}

javaScript可以参考:

$.ajax({
        url: 'http://b.fdipzone.com/server.php', // 跨域
        xhrFields:{withCredentials: true}, // 发送凭据
        dataType: 'json',
        type: 'post',
        data: {'name':'fdipzone'},
        success:function(ret){
            if(ret['success']==true){
                alert('cookie:' + ret['cookie'])
              }
        }
    });

然后JavaScript请求的时候加上此标志:withCredentials: true。
angular可以百度:“withCredentials angularJS”

3. jsonp方式

angular可以参考:

<script>
    var app = angular.module("app", []);
    app.controller("ctrl", function ($scope, $http) {
        $scope.jsonpAction = function () {
            $http.jsonp('http://localhost/Cross_Access/JsonP.php?callback=JSON_CALLBACK')
                    .success(function (data) {
                        console.log(data + '---');
                    });
        };
    });
</script>

php可以参考:

<?php
/**
 * Created by PhpStorm.
 * User: Shadow
 * Date: 2017/3/2
 * Time: 09:21
 */
//服务端返回JSON数据
$arr = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
$result = json_encode($arr);
//动态执行回调函数
$callback = $_GET['callback'];
echo $callback . "($result)";

工作方式介绍:

  • 调用 $http.jsonp方法时,会根据所传参数,在当前网页创建一个”Script”标签
<script type="text/javascript" src="http://localhost/Cross_Access/JsonP.php?callback= angular.callbacks._1" async=""></script>

其中 JSON_CALLBACK 被Angular自动替换为了angular.callbacks._x _x为Angular定义的请求序列,angular会自动生成一个_x的同名方法存放到angular.callbacks 中去

  • 当标签生效http://localhost/Cross_Access/JsonP.php被下载回来时,会被当成javascript直接执行,因为我们的php端设置了返回的内容是 callback与实际数据拼接起来的一个方法,故下载的内容实际是angular.callbacks._1(xxxxxx)其会被直接执行,故若在_1(data)方法中直接将参数通过jsonp.success(function(data){})回调,那么便能直接取到相应的值

  • 移除当前网页中插入的script标签,并移除angular.callbacks中的_1(data)方法,一个完整的jsonp请求便已成功

4.代理服务器方式

前面几种方式或多或少都需要服务端人员配合,代理服务器方式可以完全不需要服务端人员配合

  • 自己写一个php,或者Java的服务端 将web项目与此项目发布到服务器,这样web项目就能直接调用此服务器的内容,然后再用此服务器调用目标服务器的内容,因为避开了浏览器的限制,因此这种方式也是能成的,但是需要注意,这种情况下因为Cookie有path和 domain的限制,因此需要截取目标服务器的Cookie,将其改为代理服务器的path和domain,否则在需要使用到Cookie的时候,由于path或domain不对,不能将Cookie转发到目标服务器。 此方式的大概流程为

这里写图片描述

  • nginx反向代理方式
    第一步: 下载安装 nginx

安装方式请百度,并确认浏览器能正常访问到 本地nginx首页:http://localhosthttp://localhost:8080(不同的系统可能nginx的默认端口号不同)

第二步: 配置nginx环境

打开nginx对应的目录,找到nginx.conf文件,以mac为例:

cd /usr/local/etc/nginx
cat nginx.conf

对于我们只需关注其中server的配置项,现将server中的注释项目全部删掉(不用担心,因为此文件还有一个nginx.conf.default的文件为默认配置的备份)

vim nginx.conf
server {
        listen       8080;#监听端口号对应localhost:8080
        #listen       80;#默认端口号对应localhost:80即localhost,80端口号可以省略不写
        server_name  localhost;#服务名称
        location / { #匹配 ‘/’时对应的配置
            root   html; # 根目录对应为 相对目录 mac上为 /usr/local/opt/nginx/html 
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
}

其中 location /中配置的root为我们的web页面需要放置的目录,在mac上默认为 /usr/local/opt/nginx/html

cd /usr/local/opt/nginx/html

进入此目录可以看到里面有个index.html的文件,就是本地nginx首页:http://localhosthttp://localhost:8080所对应的原文件,我们改了其内容,然后在浏览器刷新后能看到变化。
可以将 root 后面的 html默认的相对位置改为我们自己的目录,比如:

location / {
    root /Users/Shadow/Sites;
}

然后进入对应目录:

cd /Users/Shadow/Sites
touch index.html
echo Hello nginx > index.html

保存nginx.conf并重新加载nginx配置文件:

nginx -s reload

在此之前还可以使用

nginx -t

命令检查nginx.conf文件的有效性 刷新http://localhost页面,可以看到

这里写图片描述

到此为止,nginx的环境已经配置好了

步骤三 部署项目

以testNGINX 项目为例 在/Users/Shadow/Sites/目录下新建项目,新建文件 testNginx.html文件输入以下内容:

https://m.douban.com/rexxar/api/v2/community_center?for_mobile=true

<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="angular.js"></script>
</head>
<body ng-controller="myCtrl">
<input type="button" value="开始请求" ng-click="action()">
</body>
<script>
    var url = "https://m.douban.com/rexxar/api/v2/community_center?for_mobile=true";
    var app = angular.module("app", []).controller("myCtrl", function ($scope, $http) {
        $scope.action = function () {
            $http.get(url).success(function (data) {
                console.log(data);
            }).error(function (e) {
                console.log(e);
            });
        }
    })
</script>
</html>

在浏览器打开
http://localhost/testNGINX/testNGINX.html
并点击开始请求按钮,然后查看日志,发生跨域问题 No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost’ is therefore not allowed access. 解决这个问题,需要修改nginx的配置文件:

cd /usr/local/etc/nginx 
vim nginx.conf 

在 server中添加如下内容:

location /douban/{
        proxy_pass https://m.douban.com/;
        proxy_cookie_path / /douban;
    }

修改 testNGINX.html的请求地址为:
var url = “https://localhost/douban/rexxar/api/v2/community_center?for_mobile=true“;
重新加载nginx配置文件

 nginx -s reload

浏览器刷新
http://localhost/testNGINX/testNGINX.html
点击开始请求,查看日志可以看见请求成功了。

上面 location的配置的意思如下:
nginx截获路径为https://localhost/douban/的请求,并将请求转发到 https://m.douban.com/替换为proxy_pass配置的域名。
完整的Server配置:

server {
        listen       80;
        server_name  localhost;
    location / {
        root /Users/Shadow/Sites;
    }
    error_page   500 502 503 504  /50x.html;
    #relative path
    location = /50x.html {
        root   html;
    }
    #absolute path
    location /douban/{
        proxy_pass https://m.douban.com/;
        proxy_cookie_path / /douban;
    }
}

代理配置后完整的js请求方法

<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="angular.js"></script>
</head>
<body ng-controller="myCtrl">
<input type="button" value="开始请求" ng-click="action()">
</body>
<script>
    var url = "http://localhost/douban/rexxar/api/v2/community_center?for_mobile=true";
    var app = angular.module("app", []).controller("myCtrl", function ($scope, $http) {
        $scope.action = function () {
            $http.get(url).success(function (data) {
                console.log(data);
            }).error(function (e) {
                console.log(e);
            });
        }
    })
</script>
</html>

配置前后请求地址对比:

https://m.douban.com/rexxar/api/v2/community_center?for_mobile=true

http://localhost/douban/rexxar/api/v2/community_center?for_mobile=true
若配置不成功,可以优先检查如下几点:

  • nginx.conf文件是否保存并被重新加载了
  • 配置的路径是否完整,尤其需要检查后面的斜杠,斜杠有没有的差别很大,具体可以百度nginx的配置方法
  • web项目的请求地址是否改为了nginx服务器配置的地址
  • nginx首页没法打开:
    先检查nginx服务是否开启,再查看配置的根目录(root)中是否有index.html文件
  • index.html文件修改了,但是浏览器看不到变化:
    清空浏览器缓存再次查看
  • 需要发布的目录放到了根目录下,但是请求时404:
    • 查看根目录配置是否正确;
    • 请求地址是否正确;
    • 请求路径是否正确;
    • 配置文件的路径是否正确,尤其需要查看斜杠,这个特别容易忘记
  • nginx.conf文件更新了,并且重新加载了,但是请求时看不到任何变化:
    windows下,任务管理器是否打开了多个nginx的进程,可以先将nginx进程全部关闭后,重新打开一个nginx
好的,让我来介绍一下如何在Nginx配置前端跨域访问以及压缩文件。 1. 配置前端跨域访问。在Nginx配置文件中加入以下内容: ``` location /api { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT'; add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization'; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT'; add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization'; return 204; } } ``` 这里的`/api`是你的后端接口路径,`Access-Control-Allow-Origin`表示允许的跨域来源,`Access-Control-Allow-Methods`表示允许的跨域请求方法,`Access-Control-Allow-Headers`表示允许的跨域请求头信息。 2. 配置文件压缩。在Nginx配置文件中加入以下内容: ``` gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; ``` 这里的`gzip on`表示开启压缩,`gzip_types`表示需要压缩的文件类型。 配置完成后,Nginx会自动对需要压缩的文件进行压缩,然后发送给客户端浏览器。 3. 保存并退出配置文件,然后重启Nginx服务器: ``` sudo systemctl restart nginx ``` 现在,你已经成功在Nginx配置了前端跨域访问和文件压缩。如果你的前端项目和后端项目在不同的域名或者端口下,可以通过配置跨域访问来实现数据交互。同时,压缩文件可以减小文件大小,提高网页加载速度,优化用户体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值