ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
- 浏览器是先执行还是先判断? 先执行后判断 - 如何判断? 跨域请求的请求头中多了一个Origin字段,这个字段的值是当前的域名信息。也就说:浏览器发现本次请求是跨域请求时,就会在请求头中增加一个Origin字段,然后等待服务器响应返回之后,判断响应头中有没有允许Origin跨域的信息,如果有则OK,如果没有则就会报错。 在doFilter方法中加入以下代码: ``` HttpServletResponse res = (HttpServletResponse) response; res.addHeader("Access-Control-Allow-Origin", "http://localhost:8080"); res.addHeader("Access-Control-Allow-Methods", "GET"); chain.doFilter(request, response); ``` 以上代码只允许一个域名的跨域,只允许GET请求,如果想允许多个域名跨域,多个请求方法,代码修改为: ``` res.addHeader("Access-Control-Allow-Origin", "*"); res.addHeader("Access-Control-Allow-Methods", "*"); ``` *思考:Origin设置为*,是不是可以满足所有的场景呢?* # 简单请求和非简单请求 针对 “浏览器是先执行还是先判断?”的问题,答案是: 浏览器发送跨域请求时,会判断请求是否是简单请求。**如果是简单请求,则会先执行,后判断;如果是非简单请求,则会先判断(发送一个预检命令,检查通过后,才会发送真正的请求),后请求**。 ## 概念 ### 简单请求 1. request methods为以下几种: get head post 2. request header里面 1. 无自定义头 2. Content-Type为以下几种: - text/plain - multipart/form-data - application/x-www-form-urlencoded ### 非简单请求 1. request methods为以下几种: put delete 2. request header里面 1. 有自定义头 2. Content-Type为 - application/json ## OPTIONS预检命令 request methods是OPTIONS。是在发送Content-Type=application/json形式的请求之前发送的一个命令。 发送OPTIONS请求时,浏览器会报如下错误: ``` Request header field Content-Type is not allowed by Access-Control-Headers in preflight response. ``` 错误的意思是:发送OPTIONS请求时请求头里面会有一个Access-Control-Request-Headers字段,字段值是content-type,但是响应头中没有允许。所以解决办法就是在Filter中增加一个响应头。 ``` res.addHeader("Access-Control-Allow-Headers", "Content-Type"); ``` ## OPTIONS预检命令的缓存 发送json形式的请求时,每次都会发送两次请求:一次OPTIONS请求,一次真正的业务请求。这样非常浪费资源,影响效率。解决问题的办法是:可以增加一个响应头,缓存预检命令。 ``` res.addHeader("Access-Control-Max-Age", "3600"); ``` 意思是:告诉浏览器,在3600秒之内缓存请求信息,不需要多次发送预检命令 # 带有Cookie的跨域 http中的回话,也就是session,是依赖于cookie来实现的,sessionId存放在cookie中 在之前的讲解中提到:"Access-Control-Allow-Origin":"*"?这句代码中的*能满足所有的使用场景吗?答案是:NO!NO!NO! 发送带有cookie的跨域请求时: 1. Access-Control-Allow-Origin需要全匹配,不能是*号只能是本域 2. 需要添加`` res.addHeader("Access-Control-Allow-Credentials", "true")`` 3. 前端以jquery为例 ``` $.ajax({ type: 'get', url: 'getCookie.do', xhrFields: { withCredentials: true }, success (json) { } }) ``` 由于现在Origin是全匹配,那么也就是只能允许一个域名的跨域调用,如果其他域名也要可跨域调用,此时该如何解决? 解决办法是:可以获取到request headers中的Origin字段,然后动态的写入Origin即可 ``` String origin = req.getHeader("Origin"); if (!StringUtils.isEmpty(origin)) { res.addHeader("Access-Control-Allow-Origin", origin); } ``` # 带自定义头的跨域 前端: ``` $.ajax({ type: 'get', url: 'getHeader.do', headers: { // 添加自定义头方法1 'x-header1': 'AAA', }, beforeSend (xhr) { // 添加自定义头方法2 xhr.setRequestHeader('x-header2', 'BBB') }, success (json) { } }) ``` 后端: ``` String headers= req.getHeader("Access-Control-Allow-Headers"); if (!StringUtils.isEmpty(headers)) { res.addHeader("Access-Control-Allow-Headers", headers ); } ```