-
/* 一.浏览器多管闲事-----------------------------------------------------搞定浏览器: 让浏览器滚,不判断 1.启动浏览器的时候加参数 2.浏览器跨域插件 二.浏览器判断类型: XHR (XMLHttpRequest)-------------------------------发送类型不是XHR, JSONP就是利用这一条. JSONP一个非官方的协议, JSONP的弊端: 1.JSONP需要后台配合, 要有一个参数, 默认是?callback=JQuery1234567... JSONP返回的类型是:javascript, 而非json 2.只可以发送get请求 3.发送的不是XHR请求(这也是它可以跨域的原因),没有回调及事件的特性 三.浏览器判断跨域: 协议, 域名, 端口, 任何一个不一样就是跨域-----------1.服务器告诉浏览器可以跨域. 2.前端通过代理欺骗浏览器是同一个域名 1.后端处理: a)应用服务器(TOMCAT)--Filter, "Access-Control-Allow-Origin": "http://localhost:8081" "Access-Control-Allow-Methods": "GET" "Access-Control-Allow-Headers": "Content-Type, custom-header1, custom-header2" //非简单请求每次会发出去两次请求,预检命令(OPTIONS)和真正的请求 "Access-Control-Max-Age": "3600" //预检命令(OPTIONS)为1个小时, 这样1个小时内就不用发送两次请求 "Access-Control-Allow-Credentials": "true" //不是"Access-Control-Allow-Origin": "*"就无敌了, 带Cookie的请求就行不通! b)HTTP服务器(NGINX) 配置比apache简单些 c)HTTP服务器(APACHE) 相对nginx复杂一些 d)Spring框架解决方案 @CrossOrigin 2.前端处理(隐藏跨域): a)反向代理-NGINX配置 在请求的时候写相对路径就行, 浏览器认为请求是同域的, 不会做跨域判断. 后端处理时, 请求地址都是绝对路径 b)反向代理-APACHE配置 以上一,二,三个条件必需同时满足, 才会生跨域问题! 问答: -> 为什么已经返回200了还报错: 因为是先发送, 浏览器再判断是否跨域. 如果存在跨域条件, 则报错. */
查看全部 -
JSONP的弊端:
服务器需要改动代码支持-如果调用的接口不是我们自己的,那么改动就很麻烦
只支持GET方法,JSONP是通过动态创建一个script发送请求的,而script只支持GET方法
发送的不是XHR请求,XHR有许多新的特性,如异步、各种事件等,JSONP则没有
查看全部 -
从服务端解决跨域问题:
(1)被调用方解决跨域问题,被调用方修改代码解决。
(2)调用方解决跨域,调用方修改Apache或者Nginx静态服务器,通过静态服务器隐藏调用请求返回给前台,前台以为是同一个地址和端口的请求就解决了跨域问题。
一个请求是怎么被处理的:当一个请求从浏览器发出的时候,他会先到中间的http服务器或者叫静态服务器主要是由(apache/nginx)来处理的。中间的静态服务器收到请求后会判断是静态请求还是动态请求,和用户数据有关的就是动态请求,如图片,css,js就是静态请求,中间的静态服务器发现是静态请求时就会把请求直接处理,然后直接返回到客户端,如果是动态请求,请求从客户端发起到了中间的http服务器,中间的http服务器会把请求转发到后台的应用服务器处理完后再返回给中间的http服务器,http服务器再把请求转发到客户请求。
查看全部 -
jsonp的实现原理:
jsonp的请求类型是script,而非xhr,这样浏览器就不会做安全校验;
jsonp的返回类型是js,而非json;
jsonp请求携带一个前后台约定的参数(eg:callback),便于让后台识别是jsonp请求,后台则返回js数据而非json数据
查看全部 -
4、Filter解决跨域方案
问题1:浏览器是先执行请求还是先判断跨域?
浏览器请求-->判断响应中是否有允许跨域-->发现不允许跨域,阻止跨域
说明:当执行跨域请求时,浏览器会提示当前接口不被允许,这说明浏览器已发出了当前请求,但是它的的响应内容被拦截;如果在Response header中的Access-Control-Allow-Origin设置的允许访问源不包含当前源,则拒绝数据返回给当前源。
问题2:判断当前请求是否是跨域请求的方法?
通过查看当前请求的Request Headers 中是否存在Origin属性,当前属性存储的是当前域的信息
在被调用方解决跨域(支持跨域)通过自定义Filter来实现:
1、在SpringBoot工程创建自定拦截器CrosFilter,如图:
2、 注册自定拦截器CrosFilter,作用于全局如图:
问题3:什么是简单请求和非简单请求?
说明:浏览器在发送跨域请求时会先判断当前请求是不是简单请求,如果是简单请求浏览器则会先执行请求,再判断是否支持跨域;如果是非简单请求它会先发送一个预检命令(即OPTIONS请求),检查通过后再把当前请求发出去。
1、简单请求:
方法为GET、HEAD、POST的请求,并且请求头(header)里面没有自定义头;Content-Type为text/plain、multipart/form-data、application/x-www-form-urlencoded。
2、非简单请求:
方法为PUT、DELETE的请求,发送JSON格式的ajax请求、带自定义请求头的ajax请求。
例子:发送JSON格式的ajax请求
问题4:Access-Control-Allow-Headers是什么?有什么作用?
响应头部 Access-Control-Allow-Headers 用于 preflight request (预检请求)中,列出了将会在正式请求的 Access-Control-Expose-Headers 字段中出现的首部信息。简单首部,如 simple headers、Accept、Accept-Language、Content-Language、Content-Type (只限于解析后的值为 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 三种MIME类型(不包括参数)),它们始终是被支持的,不需要在这个首部特意列出。
问题5:Access-Control-Max-Age是什么?
浏览器的同源策略,就是出于安全考虑,浏览器会限制从脚本发起的跨域HTTP请求(比如异步请求GET, POST, PUT, DELETE, OPTIONS等等),所以浏览器会向所请求的服务器发起两次请求,第一次是浏览器使用OPTIONS方法发起一个预检请求,第二次才是真正的异步请求,第一次的预检请求获知服务器是否允许该跨域请求:如果允许,才发起第二次真实的请求;如果不允许,则拦截第二次请求。Access-Control-Max-Age用来指定本次预检请求的有效期,单位为秒,,在此期间不用发出另一条预检请求。
例如:res.addHeader("Access-Control-Max-Age", "3600"),表示隔60分钟才发起预检请求
查看全部 -
当浏览器要发送跨域请求时,如果请求是复杂请求,浏览器会先发送一个options预检命令即一个options请求,当该请求通过时才会再发送真正的请求。
该option请求会根据请求的信息去询问服务端支不支持该请求。比如发送的数据是json类型(通过content-type设置)的话,会携带一个请求头Access-Control-Request-Headers: content-type去询问支不支持该数据类型,如果支持,则请求就会通过,并发送真正的请求
查看全部 -
总结
跨域产生的原因:
浏览器限制。如果浏览器发现请求是跨域的时候,就会做校验,如果校验不通过就会报跨域的错误
跨域。发出去的请求只要域名、端口、协议中的任意一个与当前域不同的时候,都会发生跨域
发送的XHR(XMLHTTPRequest)请求。如果发送的不是xhr请求,无论是否跨域,浏览器都不会报错
只有这三种原因同时满足时,才会发生跨域
解决跨域的方法
浏览器角度。让浏览器不做校验,浏览器的设置跨域,在浏览器的属性设置页面的目标输入框加上--disable-web-security。这样浏览器将不会去做校验了。但是每个人都需要去改动,不建议使用。
发送xhr请求角度。让跨域的请求不发送xhr请求,就不会再报错了。办法是使用jsonp:jsonp是非官方协议,是前后端的一种约定,前端使用ajax发送请求,dataType为jsonp,并且带一个参数(默认是callback),当后台发现这个参数之后,就知道这是一个jsonp请求,就会把原本返回json对象编程js返回,js代码是一个函数的执行,函数名是callback的参数值,函数的参数是原本的json对象。缺点:1).只支持get方法请求;2).需要服务器修改代码;3).发送的不是xhr请求
在跨域角度。1).被调用方解决:在响应头增加指定字段,告诉浏览器,允许调用,这种方法的原理是从根源支持跨域的。各种解决方式,请参考详细解决笔记;2).调用方解决:这种解决办法原理是隐藏跨域。使用代理,在同一个域请求不同的url地址,转发到不同的域。
查看全部 -
一、解决跨域的思路:
1.被调用方解决-支持跨域(根据http协议关于跨域方面的要求,增加响应头信息,告诉浏览器允许被跨域调用)
(1)使用filter解决
res.addHeader("Access-Control-Allow-Origin", "http://localhost:8081"); //设置允许http://localhost:8081域访问,*表示所有域都能访问
res.addHeader("Access-Control-Allow-Methods", "GET");//设置允许GET方法访问,*表示所有方法
(2)nginx解决方案
(3)APACHE解决方案
(4)Spring解决方案 加@CrossOrigin注解即可
2.调用方使用代理做调用解决跨域问题-隐藏跨域
(1)使用反向代理
反向代理:访问同一个域名的两个url,会去到两个不同的服务器
二、简单请求和非简单请求
简单请求:先执行后判断
工作中常见的简单请求:
方法为:GET,HEAD,POST
请求header里面:无自定义头
Content-Type为以下几种:text/plain,multipart/form-data,application/x-www-form-urlencoded
非简单请求:先发预options预检命令,通过后再发跨域请求
res.addHeader("Access-Control-Allow-Headers", "Content-Type");//允许预检命令
res.addHeader("Access-Control-Max-Age", "3600");//预检命令缓存秒数
工作中常见的非简单请求:put,delete的请求,发送json格式的请求,带自定义头的请求
三、带Cookie的跨域请求,response中需要设置
res.addHeader("Access-Control-Allow-Credentials", "true");
res.addHeader("Access-Control-Allow-Origin", "http://localhost:8081");//带Cookie时Access-Control-Allow-Origin需要全匹配,不能用通配符
当多个域名都需要带Cookie跨域访问时,从Filter里面拿到Origin信息,把这个字段写入到Access-Control-Allow-Origin里面
String origin = req.getHeader("Origin");
if(!StringUtils.isEmpty(origin)) {
res.addHeader("Access-Control-Allow-Origin", origin);
}
注意:1. 发送的Cookie是被调用方的Cookie,不是调用方的Cookie document.cookie="cookie1=xiaofengqing"这样就能新加入一个cookie了 2.Access-Control-Allow-Origin不能使用*
四、带自定义头的跨域
//支持所有自定义头
String headers = req.getHeader("Access-Control-Request-Headers");
if(!StringUtils.isEmpty(headers)) {
res.addHeader("Access-Control-Allow-Headers",headers);
}
查看全部 -
被调用方解决跨域问题,被调用方修改代码解决。
调用方解决跨域,调用方修改Apache或者Nginx静态服务器,通过静态服务器隐藏调用请求返回给前台,前台以为是同一个地址和端口的请求就解决了跨域问题。
查看全部 -
nginx.exe -t 检查配置是否成功
start nginx.exe 启动nginx
nginx.exe -s reload 重新载入修改的配置
hosts 映射本地域名 127.0.0.1 b.com
server{
listen 80;
server_name b.com; 请求发起方 即 浏览器客户端
location /{
proxy_pass http://localhost:8080/; 服务器地址
add_header Access-Control-Allow-Methds *;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
if ($request_method = OPTIONS){
return 200;
}
}
}
查看全部 -
一、http会话session依赖于cookie, sessionid存放在cookie中。
二、ajax
1、$.ajax({
type: "get",
xhrFields: {
widthCredentials: true // 发送ajax请求的时候会带上cookie
}
})
2、cookie是加在被调用方。
服务端就是被调用方,而客户端就是调用方。在浏览器的控制台中通过document.cookie="" 来设置cookie。
3、读cookie只能读到本域的。
4、带cookie时,后台代码注意以下2点:
(1)带cookie的时候,Access-Control-Allow-Origin,必须是全匹配,如http://localhost:8081, 不能是 *,否则报错,如下:
(2)带cookie进行跨域时,需要设置以下请求头:
res.addHeader("Access-Control-Allow-Credentials", "true")
查看全部 -
简单请求和非简单请求
1.简单请求是先请求,浏览器再判断是否是跨域;而非简单请求要先发送一个预检命令,检查通过之后才会真正的把跨域请求发出去
2.非简单请求常见的是发送json格式的请求,如图contentType为“application/json;charset=utf-8”
最后的结果如下,返回了两个请求,一个是OPTIONS,另一个是POST请求,其中的OPTIONS就是一个预检命令,成功了之后才会发送后面的跨域请求
3.预检命令的缓存。因为这种非简单请求每次都会发送两次请求,其实效率是比较低的,但是如果能缓存预检命令的话,会响应的提高效率
在服务器中,添加一个响应头信息,告诉浏览器在截下来的一个小时可以缓存信息,就不需要再发送预检命令
查看全部 -
jsonp解决跨域问题的原理(区别):
①普通请求,发送请求时,请求类型type默认为 xhr ;jsonp的请求类型为 script ,不会被浏览器认为是跨域异常;
②普通请求返回的数据类型默认为 json 格式;而 jsonp 的请求返回的数据类型为 javascript 的脚本;
③普通请求的地址后面没有携带任何数据;而jsonp请求的地址后面携带了 callback为键的一组键值对数据;由下列图片可知,
当前端被设置为jsonp格式后,在后端中使用切面实现 jsonp 的格式化接口;该接口声明当返回的数据有callback这个值时,将返回的数据以jsonp的格式返回给前端,避免出现数据类型不一致的问题。
查看全部 -
我们知道非简单请求, 每次会发出两次请求, 这会影响性能. HTTP协议增加了个响应头, 可以让我们在服务端设置`Access-Control-Max-Age`来缓存预检请求, 比如说我们可以设置为3600m, 也就是一小时客户端只会在第一次的时候发送两个请求, 接下来一个小时内`OPTIONS`请求就被缓存起来了.
查看全部 -
JSONP是一个非官方协议,它是一个约定,约定了一个请求的参数里如果包含指定的参数(默认是callback)这就是一个JSONP请求,服务发现是一个JSONP请求时就会把返回的值由原来的JSON对象改变JS代码,JS的代码的内容是函数调用的形式。他的函数名是callback参数的值,他的函数的参数是原来 要返回的JSON对象
查看全部
举报