关于先后端分离跨域请求问题

1.问题描述:

  在使用react开发时遇到了先后端分离post请求跨域的问题,致使请求没法正常完成。javascript

2.什么是跨域?

  当客户端向服务器发起一个网络请求,url会有包含三个主要信息:协议(protocol),域名(host),端口号(port)。当三部分都和服务器相同的状况下,属于同源。可是只要有一个不一样,就属于构成了跨域调用。会受到同源策略的限制。html

  同源策略限制从一个源加载的文档或脚本如何与来自另外一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScript)对不一样域的服务进行跨站调用(一般指使用XMLHttpRequest请求)。
java

3.几种跨域解决方式:

3.1. jsonp请求:

  JSONP(json with padding 填充式json),利用了使用src引用静态资源时不受跨域限制的机制。主要在客户端搞一个回调作一些数据接收与操做的处理,并把这个回调函数名告知服务端,而服务端须要作的是按照javascript的语法把数据放到约定好的回调函数之中便可。jQuery很早以前就已经吧JSONP语法糖化了,使用起来会更加方便。react

  jsonp的简单实现:jquery

 1 // 回调函数
 2 function jsonpCallback(data) {
 3     console.log("jsonpCallback: " + data.name)
 4 }
 5 $("#submit").click(function() {
 6     var data = {
 7         name: $("#name").val(),
 8         id: $("#id").val()
 9     };
10     $.ajax({
11         url: 'http://localhost:3001/ajax/deal',
12         data: data,
13         dataType: 'jsonp',
14         cache: false,
15         timeout: 5000,
16         // jsonp 字段含义为服务器经过什么字段获取回调函数的名称
17         jsonp: 'callback',
18         // 声明本地回调函数的名称,jquery 默认随机生成一个函数名称
19         jsonpCallback: 'jsonpCallback',
20         success: function(data) {
21             console.log("ajax success callback: " + data.name)
22         },
23         error: function(jqXHR, textStatus, errorThrown) {
24             console.log(textStatus + ' ' + errorThrown);
25         }
26     });
27 });

 

3.2 cors跨域资源共享

  CORS(Cross-origin resource sharing 跨域资源共享),依附于AJAX,经过添加HTTP Hearder部分字段请求与获取有权限访问的资源。CORS对开发者是透明的,由于浏览器会自动根据请求的状况(简单和复杂)作出不一样的处理。CORS的关键是服务端的配置支持。因为CORS是W3C中一项较“新”的方案,以致于各大网页解析引擎尚未对其进行严格规格的实现,因此不一样引擎下可能会有一些不一致。webpack

  (1)Access-Control-Allow-Originnginx

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

  (2)Access-Control-Allow-Credentialsajax

该字段可选。它的值是一个布尔值,表示是否容许发送Cookie。默认状况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie能够包含在请求中,一块儿发给服务器。这个值也只能设为true,若是服务器不要浏览器发送Cookie,删除该字段便可。若是要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其余域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也没法读取服务器域名下的Cookie。json

  (3)Access-Control-Expose-Headers

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

  java过滤器实现cors:

 1 public class CorsFilter implements Filter {
 2 
 3     public void init(FilterConfig filterConfig) throws ServletException {
 4     }
 5 
 6     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
 7         throws IOException, ServletException {
 8         HttpServletResponse httpResponse = (HttpServletResponse) response;
 9         httpResponse.setHeader("Access-Control-Allow-Origin", "http://localhost:8081");//设置容许跨域的域名,须要发送cookie信息,因此此处须要指定具体的域名,
10         httpResponse.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
11         httpResponse.setHeader("Access-Control-Allow-Methods", "GET, PUT, DELETE, POST");//容许跨域的请求方式
12         /**
13          * ajax请求的时候若是带有xhrFields:{withCredentials:true},
14          * 那么服务器后台在配置跨域的时候就必需要把Access-Control-Allow-Credentials这个请求头加上去
15          */
16         httpResponse.setHeader("Access-Control-Allow-Credentials", "true");//容许发送Cookie信息
17         httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // 支持HTTP 1.1.
18         httpResponse.setHeader("Pragma", "no-cache"); // 支持HTTP 1.0. response.setHeader("Expires", "0");
19         chain.doFilter(request, response);
20     }
21 
22     public void destroy() {
23         // TODO Auto-generated method stub
24     }
25 }

 

jsonp和cors的不一样:

  二者优势与缺点大体互补,放在一块介绍:

  1. JSONP的主要优点在于对浏览器的支持较好;虽然目前主流浏览器支持CORS,但IE10如下不支持CORS。
  2. JSONP只能用于获取资源(即只读,相似于GET请求);CORS支持全部类型的HTTP请求,功能完善。(这点JSONP被玩虐,但大部分状况下GET已经能知足需求了)
  3. JSONP的错误处理机制并不完善,咱们没办法进行错误处理;而CORS能够经过onerror事件监听错误,而且浏览器控制台会看到报错信息,利于排查。
  4. JSONP只会发一次请求;而对于复杂请求,CORS会发两次请求
  5. 始终以为安全性这个东西是相对的,没有绝对的安全,也作不到绝对的安全。毕竟JSONP并非跨域规范,它存在很明显的安全问题:callback参数注入和资源访问受权设置。CORS好歹也算是个跨域规范,在资源访问受权方面进行了限制(Access-Control-Allow-Origin),并且标准浏览器都作了安全限制,好比拒绝手动设置origin字段,相对来讲是安全了一点。
    可是回过头来看一下,就算是不安全的JSONP,咱们依然能够在服务端端进行一些权限的限制,服务端和客户端也都依然能够作一些注入的安全处理,哪怕被攻克,它也只能读一些东西。就算是比较安全的CORS,一样能够在服务端设置出现漏洞或者不在浏览器的跨域限制环境下进行攻击,并且它不只能够读,还能够写。

3.3. react经过webpack配置代理实现跨域请求:

  代理的话其实也可使用nginx反向代理,可是配置的时候发现请求过程老是处于(pending)等待状态,好久才能响应,不知是何缘由引发,还未解决,若有大牛看到,肯请指教。

nginx配置以下:

 1 location ^~/ {
 2              proxy_pass http://localhost:8080;
 3              proxy_redirect default ;
 4              proxy_set_header Host $host:80;
 5              proxy_set_header X-Real-IP $remote_addr;
 6              proxy_set_header REMOTE-HOST $remote_addr;
 7              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 8              
 9             
10         }

  由于失败了,因此转而使用webpack代理配置:

  首先在webpack.config.js中进行配置:

module.exports = {
  //。。。省略

devServer: {
            port: '8081',
            host: '127.0.0.1',
            historyApiFallback: false,
            disableHostCheck: true,
            noInfo: false,
            stats: 'minimal',
            inline: true,
            //开启服务器的模块热替换(HMR)
            hot: true,
            // 和上文 output 的“publicPath”值保持一致
            publicPath: context,
            proxy: { '/sharemeeting/*': { target: "http://localhost:8080", changeOrigin: true, secure: false } }
        }
    //。。。省略
};

 

 

   proxy中,'/sharemeeting/*'是过滤要代理的请求的路径,tartget为代理后的目标服务器地址,包括协议、域名、端口号信息。若是发起的请求为http://localhost:8081/sharemeeting/getTest.do。那么将会被代理为http://localhost:8080/sharemeeting/getTest.do

  fetch请求

 

 1       let url = "/sharemeeting/login/getTest.do";
 2         fetch(url,{
 3             method: 'POST',
 4             headers: {
 5                 'Accept': 'application/json',
 6                 'Content-Type': 'application/json'
 7             },
 8             credentials: 'include',
 9             body: JSON.stringify({})
10         }).then((response) => response.json()) //把response转为json
11           .then((responseData) => { // 上面的转好的json
12                 if(responseData.status === false){
13                     window.location.href="#/";
14                 }else{
15                     this.reset(responseData.data);
16                 }
17             }).catch((error)=> {
18             window.location.href="#/";
19         })

 

 

 

  请求的url要像上面这样定义,若是这样定义,这样请求的时候会本身添加上协议和请求的域名端口号,

 

 

======================================参考=================================

1.https://www.zhihu.com/question/41992168 JS跨域方案JSONP与CORS的各自优缺点以及应用场景?

2.http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html 浏览器同源政策及其规避方法

3.http://www.ruanyifeng.com/blog/2016/04/cors.html 跨域资源共享 CORS 详解

4.https://www.jianshu.com/p/3bdff821f859 Webpack dev server使用http-proxy解决跨域问题

相关文章
相关标签/搜索