在使用react开发时遇到了先后端分离post请求跨域的问题,致使请求没法正常完成。javascript
当客户端向服务器发起一个网络请求,url会有包含三个主要信息:协议(protocol),域名(host),端口号(port)。当三部分都和服务器相同的状况下,属于同源。可是只要有一个不一样,就属于构成了跨域调用。会受到同源策略的限制。html
同源策略限制从一个源加载的文档或脚本如何与来自另外一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScript)对不一样域的服务进行跨站调用(一般指使用XMLHttpRequest请求)。
java
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 });
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-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。若是想拿到其余字段,就必须在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 }
二者优势与缺点大体互补,放在一块介绍:
代理的话其实也可使用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解决跨域问题