国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

cors跨域之簡單請(qǐng)求與預(yù)檢請(qǐng)求(發(fā)送請(qǐng)求頭帶令牌token)

RaoMeng / 704人閱讀

摘要:所以跨域請(qǐng)求分兩種簡單請(qǐng)求和預(yù)檢請(qǐng)求。但對(duì)于第二個(gè)錯(cuò)誤,好像沒法向第一種那樣,將預(yù)檢請(qǐng)求轉(zhuǎn)變?yōu)楹唵握?qǐng)求,所以,只有尋找方法怎么在后端實(shí)現(xiàn)相應(yīng)的預(yù)檢請(qǐng)求,來返回一個(gè)狀態(tài)碼,告訴瀏覽器此次跨域請(qǐng)求可以繼續(xù)。

引子

自從從JAVA偽全棧轉(zhuǎn)前端以來,學(xué)習(xí)的路上就充滿了荊棘(奇葩問題),而涉及前后端分離這個(gè)問題,對(duì)cors的應(yīng)用不斷增多,暴露出的問題也接踵而至。
這兩天動(dòng)手實(shí)踐基于Token的WEB后臺(tái)認(rèn)證機(jī)制,看過諸多理論(較好一篇推薦),正所謂慮一千次,不如去做一次。 猶豫一萬次,不如實(shí)踐一次,所以就有了下文,關(guān)于token的生成,另外一篇文章會(huì)細(xì)講,本篇主要討論在發(fā)送ajax請(qǐng)求,頭部帶上自定義token驗(yàn)證驗(yàn)證,暴露出的跨域問題。

先說說定義

CORS:跨來源資源共享(CORS)是一份瀏覽器技術(shù)的規(guī)范,提供了 Web 服務(wù)從不同網(wǎng)域傳來沙盒腳本的方法,以避開瀏覽器的同源策略,是 JSONP 模式的現(xiàn)代版。與 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以讓網(wǎng)頁設(shè)計(jì)師用一般的 XMLHttpRequest,這種方式的錯(cuò)誤處理比JSONP要來的好,JSONP對(duì)于 RESTful 的 API 來說,發(fā)送 POST/PUT/DELET 請(qǐng)求將成為問題,不利于接口的統(tǒng)一。但另一方面,JSONP 可以在不支持 CORS 的老舊瀏覽器上運(yùn)作。不過現(xiàn)代的瀏覽器(IE10以上)基本都支持 CORS。
預(yù)檢請(qǐng)求(option):在 CORS 中,可以使用 OPTIONS 方法發(fā)起一個(gè)預(yù)檢請(qǐng)求(一般都是瀏覽檢測到請(qǐng)求跨域時(shí),會(huì)自動(dòng)發(fā)起),以檢測實(shí)際請(qǐng)求是否可以被服務(wù)器所接受。預(yù)檢請(qǐng)求報(bào)文中的 Access-Control-Request-Method 首部字段告知服務(wù)器實(shí)際請(qǐng)求所使用的 HTTP 方法;Access-Control-Request-Headers 首部字段告知服務(wù)器實(shí)際請(qǐng)求所攜帶的自定義首部字段。服務(wù)器基于從預(yù)檢請(qǐng)求獲得的信息來判斷,是否接受接下來的實(shí)際請(qǐng)求。

OPTIONS /resources/post-here/ HTTP/1.1 
Host: bar.other 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-us,en;q=0.5 
Accept-Encoding: gzip,deflate 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 
Connection: keep-alive 
Origin: http://foo.example 
Access-Control-Request-Method: POST 
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

服務(wù)器所返回的 Access-Control-Allow-Methods 首部字段將所有允許的請(qǐng)求方法告知客戶端。該首部字段與 Allow 類似,但只能用于涉及到 CORS 的場景中。

問題描述

話不多說,先上代碼:

前端(ajax庫:vue-resource)
        userLogin:function(){
            this.$http({
                method:"post",
                url:"http://localhost:8089/StockAnalyse/LoginServlet",
                params:{"flag":"ajaxlogin","loginName":this.userInfo.id,"loginPwd":this.userInfo.psd}, 
                headers: {"Content-Type": "application/x-www-form-urlencoded"}, 
                credientials:false, 
                emulateJSON: true                    
            }).then(function(response){
                sessionStorage.setItem("token",response.data);
                this.isActive =false;
                document.querySelector("#showInfo").classList.toggle("isLogin");
            })                 
        }
后端相關(guān)配置:
        response.setHeader("Access-Control-Allow-Origin", "http://localhost"); //允許來之域名為http://localhost的請(qǐng)求        
    response.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");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); //請(qǐng)求允許的方法
    response.setHeader("Access-Control-Max-Age", "3600");    //身份認(rèn)證(預(yù)檢)后,xxS以內(nèi)發(fā)送請(qǐng)求不在需要預(yù)檢,既可以直接跳過預(yù)檢,進(jìn)行請(qǐng)求(前面只是照貓畫虎,后面才理解)

關(guān)于上面一段代碼,是我的用戶首次登錄認(rèn)證,生成token令牌,保存在sessionStorage中,供后面調(diào)用;需要說明的是,前端服務(wù)器地址是:localhost:80,后端服務(wù)器地址:localhost:8089,所以前后端涉及到跨域,自己在后端做了相應(yīng)的跨域設(shè)置:response.setHeader("Access-Control-Allow-Origin", "http://localhost"); 所以登錄認(rèn)證,安全的實(shí)現(xiàn)了跨域信息認(rèn)證,后端相應(yīng)發(fā)送回來了相應(yīng)的token信息。
但獲取到token后,想在需要的時(shí)候,在請(qǐng)求的頭部攜帶上這個(gè)令牌,來做相應(yīng)的身份認(rèn)證,所以自己在請(qǐng)求中做了這些改動(dòng)(有標(biāo)注),后端沒改動(dòng),源碼:

        checkIdentity:function(){
            let token =sessionStorage.getItem("token");
            this.$http({
                method:"post",
                url:"http://localhost:8089/StockAnalyse/LoginServlet",
                params:{"flag":"checklogin","isLogin":true,"token":token}, 
                headers: {"Content-Type": "application/x-www-form-urlencoded"}, 
                headers:{"token":token},        //header中攜帶令牌信息            
                credientials:false, 
                emulateJSON: true                    
            }).then(function(response){
                console.log(response.data);
            })                 
        }   

但實(shí)際上在devtools打印了如下錯(cuò)誤信息:Response to preflight request doesn"t pass access control check: No "Access-Control-Allow-Origin" header is present on the requested resource. Origin "http://localhost" is therefore not allowed access.仔細(xì)想一想,好像,似乎這個(gè)問題遇到過,還提過問,確實(shí)提過,鏈接在這里。但這次的設(shè)置和上次一樣,就在header里多加了一個(gè)自定義token,但卻報(bào)了和上次沒有設(shè)置headers: {"Content-Type": "application/x-www-form-urlencoded"}一樣的錯(cuò)誤信息,于是,不知所措,算了,重頭再來,好好百度,研究一下cors跨域。

理論學(xué)習(xí)

運(yùn)氣不錯(cuò),找到了一篇好文,文章講的很細(xì),也找到自己問題的所在:觸發(fā) CORS 預(yù)檢請(qǐng)求。引用原文的話加以自己總結(jié):跨域資源共享標(biāo)準(zhǔn)新增了一組 HTTP 首部字段,允許服務(wù)器聲明哪些源站有權(quán)限訪問哪些資源。另外,規(guī)范要求,對(duì)那些可能對(duì)服務(wù)器數(shù)據(jù)產(chǎn)生副作用的 HTTP 請(qǐng)求方法(特別是 GET 以外的 HTTP 請(qǐng)求,或者搭配某些 MIME 類型的 POST 請(qǐng)求),瀏覽器必須首先使用 OPTIONS 方法發(fā)起一個(gè)預(yù)檢請(qǐng)求(preflight request:似曾相識(shí)有沒有?誒,對(duì),上面那個(gè)錯(cuò)誤信息中,就有一個(gè)這樣陌生的詞匯),從而獲知服務(wù)端是否允許該跨域請(qǐng)求。服務(wù)器確認(rèn)允許之后,才發(fā)起實(shí)際的 HTTP 請(qǐng)求。在預(yù)檢請(qǐng)求的返回中,服務(wù)器端也可以通知客戶端,是否需要攜帶身份憑證(包括 Cookies 和 HTTP 認(rèn)證相關(guān)數(shù)據(jù))。所以跨域請(qǐng)求分兩種:簡單請(qǐng)求和預(yù)檢請(qǐng)求。一次完整的請(qǐng)求不需要服務(wù)端預(yù)檢,直接響應(yīng)的,歸為簡單請(qǐng)求;而響應(yīng)前需要預(yù)檢的,稱為預(yù)檢請(qǐng)求,只有預(yù)檢請(qǐng)求通過,才有接下來的簡單請(qǐng)求。對(duì)于那些是簡單請(qǐng)求,那些會(huì)觸發(fā)預(yù)檢請(qǐng)求,文章做了詳細(xì)的總結(jié),這里列出觸發(fā)預(yù)檢請(qǐng)求的條件(不知道腦子為啥會(huì)想到那些會(huì)觸發(fā)BFC的條件),不要跑題,原文是這樣總結(jié)的:

當(dāng)請(qǐng)求滿足下述任一條件時(shí),即應(yīng)首先發(fā)送預(yù)檢請(qǐng)求:
使用了下面任一 HTTP 方法:
PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH
人為設(shè)置了對(duì) CORS 安全的首部字段集合之外的其他首部字段。該集合為:
Accept
Accept-Language
Content-Language
Content-Type (but note the additional requirements below)
DPR
Downlink
Save-Data
Viewport-Width
Width
 Content-Type 的值不屬于下列之一:
application/x-www-form-urlencoded
multipart/form-data
text/plain
問題分析

所以,再來看自己兩次犯錯(cuò)(第一次是沒有設(shè)置:headers: {"Content-Type": "application/x-www-form-urlencoded"}, 第二次是設(shè)置自定義header,headers:{"token":token}。很巧,有沒有,一次少,一次多,都點(diǎn)燃了導(dǎo)火索),其實(shí)都是觸發(fā)了預(yù)檢請(qǐng)求。對(duì)于第一次的錯(cuò)誤,很好解決,增加headers: {"Content-Type": "application/x-www-form-urlencoded"},就解決了,關(guān)于Conten-Type的幾種取值,你需要知道的。但對(duì)于第二個(gè)錯(cuò)誤,好像沒法向第一種那樣,將預(yù)檢請(qǐng)求轉(zhuǎn)變?yōu)楹唵握?qǐng)求,所以,只有尋找方法怎么在后端實(shí)現(xiàn)相應(yīng)的預(yù)檢請(qǐng)求,來返回一個(gè)狀態(tài)碼2xx,告訴瀏覽器此次跨域請(qǐng)求可以繼續(xù)。所以注意力轉(zhuǎn)向后端。
關(guān)于JAVA實(shí)現(xiàn)預(yù)檢請(qǐng)求,基本都是采用過濾器,不要問我為什么不是監(jiān)聽器或者攔截器(我就是個(gè)偽全棧,就不要相互為難了,自己百度之),自定義(copy)了一個(gè)filter,并在web.xml中進(jìn)行了設(shè)置。源碼:

Filter接口實(shí)現(xiàn)部分:
package stock.model;
import java.io.IOException;   
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;    
import org.apache.commons.httpclient.HttpStatus;   //這里需要添加commons-httpclient-3.1.jar
public class CorsFilter implements Filter {     //filter 接口的自定義實(shí)現(xiàn)
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        response.setHeader("Access-Control-Allow-Origin", "*");           
        String token = request.getHeader("token");
        System.out.println("filter origin:"+token);//通過打印,可以看到一次非簡單請(qǐng)求,會(huì)被過濾兩次,即請(qǐng)求兩次,第一次請(qǐng)求確認(rèn)是否符合跨域要求(預(yù)檢),這一次是不帶headers的自定義信息,第二次請(qǐng)求會(huì)攜帶自定義信息。
        if ("OPTIONS".equals(request.getMethod())){//這里通過判斷請(qǐng)求的方法,判斷此次是否是預(yù)檢請(qǐng)求,如果是,立即返回一個(gè)204狀態(tài)嗎,標(biāo)示,允許跨域;預(yù)檢后,正式請(qǐng)求,這個(gè)方法參數(shù)就是我們?cè)O(shè)置的post了
          response.setStatus(HttpStatus.SC_NO_CONTENT); //HttpStatus.SC_NO_CONTENT = 204
          response.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, OPTIONS, DELETE");//當(dāng)判定為預(yù)檢請(qǐng)求后,設(shè)定允許請(qǐng)求的方法
          response.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, Token"); //當(dāng)判定為預(yù)檢請(qǐng)求后,設(shè)定允許請(qǐng)求的頭部類型
          response.addHeader("Access-Control-Max-Age", "1");  // 預(yù)檢有效保持時(shí)間                       
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override
    public void destroy() {     
    }
}
web.xml配置部分

cors
stock.model.CorsFilter


cors
/*
   
關(guān)于Access-Control-Max-Age

最近又開始寫java,再回來看這個(gè),發(fā)現(xiàn)當(dāng)時(shí)Access-Control-Max-Age設(shè)置了1.其實(shí)這樣寫有很大問題,因?yàn)槊總€(gè)復(fù)雜請(qǐng)求都會(huì)發(fā)兩次。顯然這樣是當(dāng)代所不能接受的,所以Max-Age的值適合設(shè)的大一些,具體多大很業(yè)務(wù)需求相關(guān)。另外Access-Control-Max-Age不是針對(duì)請(qǐng)求域名有效的,是請(qǐng)求的完成路徑有效的,比如第一次發(fā)出www.exanple.com/api/corsGet,會(huì)產(chǎn)生一次options請(qǐng)求和一次post請(qǐng)求,然后我再請(qǐng)求一次,這時(shí)沒有預(yù)檢請(qǐng)求了,只有post請(qǐng)求。但再發(fā)送一次www.exanple.com/api/corsSave請(qǐng)求,會(huì)發(fā)現(xiàn)又產(chǎn)生了一次options請(qǐng)求和一次post請(qǐng)求,所以Access-Control-Max-Age不是針對(duì)相同的origin有效,而是針對(duì)相同的requestUrl有效。很重要哦。

結(jié)論

當(dāng)在后端實(shí)現(xiàn)添加上面的源碼后,皆大歡喜,問題得以解決,補(bǔ)上失敗和成功,自己截下的兩張請(qǐng)求響應(yīng)圖。仔細(xì)看請(qǐng)求響應(yīng)失敗發(fā)起響應(yīng)那張圖,在General的數(shù)據(jù)集中,可以看到方法是options,而非代碼指定的post請(qǐng)求,所以這是一次瀏覽器發(fā)出的一次預(yù)檢請(qǐng)求,讓服務(wù)器確認(rèn)此IP是否有訪問的權(quán)限,如果有,服務(wù)器需要返回一個(gè)2xx的狀態(tài)碼給瀏覽器。緊接著再發(fā)起一次簡單請(qǐng)求。如下面在devtools中的截取圖片(為了對(duì)比清除,我把兩次分別截取,做了拼接,因?yàn)椴粫?huì)做動(dòng)態(tài)圖)。可以看到同一個(gè)post請(qǐng)求,實(shí)際上產(chǎn)生了兩次網(wǎng)絡(luò)連接。
但關(guān)于cors,要去探索的,還有很多很多,所以遵循革命語錄:實(shí)踐(有時(shí)也可以是時(shí)間)是檢驗(yàn)真理的唯一標(biāo)準(zhǔn),是沒有錯(cuò)的。后續(xù)有新的收獲,再補(bǔ)充。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/67240.html

相關(guān)文章

  • cors域之簡單請(qǐng)求預(yù)檢請(qǐng)求發(fā)送請(qǐng)求頭帶令牌token

    摘要:所以跨域請(qǐng)求分兩種簡單請(qǐng)求和預(yù)檢請(qǐng)求。但對(duì)于第二個(gè)錯(cuò)誤,好像沒法向第一種那樣,將預(yù)檢請(qǐng)求轉(zhuǎn)變?yōu)楹唵握?qǐng)求,所以,只有尋找方法怎么在后端實(shí)現(xiàn)相應(yīng)的預(yù)檢請(qǐng)求,來返回一個(gè)狀態(tài)碼,告訴瀏覽器此次跨域請(qǐng)求可以繼續(xù)。 引子 自從從JAVA偽全棧轉(zhuǎn)前端以來,學(xué)習(xí)的路上就充滿了荊棘(奇葩問題),而涉及前后端分離這個(gè)問題,對(duì)cors的應(yīng)用不斷增多,暴露出的問題也接踵而至。這兩天動(dòng)手實(shí)踐基于Token的WE...

    zsy888 評(píng)論0 收藏0
  • 前端域之原因&&方案&&原理

    摘要:于是乎同源策略應(yīng)運(yùn)而生主要限制在于和無法讀取。怎么繞過同源策略首先一般來說協(xié)議和端口造成的跨域問題大部分方法是沒有辦法繞過的。二級(jí)域名是寄存在主域名之下的域名。當(dāng)主域名受到懲罰二級(jí)域名也會(huì)連帶懲罰。 前言 這是一道前端跨不過躲不掉面試必備的知識(shí),掙扎多年沒能做到刻骨銘心深入脊髓,只能好好寫篇博文記錄起來了; 什么是跨域? 廣義來說,A域執(zhí)行的文檔腳本試圖去請(qǐng)求B域下的資源是不被允許的,...

    Zack 評(píng)論0 收藏0
  • CORS原理及@koa/cors源碼解析

    摘要:服務(wù)端根據(jù)這個(gè)值,決定是否同意本次請(qǐng)求。預(yù)檢請(qǐng)求預(yù)檢請(qǐng)求用的請(qǐng)求方法是,表示這個(gè)請(qǐng)求是用來詢問的。該字段也可以設(shè)為星號(hào),表示同意任意跨源請(qǐng)求。這是為了避免多次預(yù)檢請(qǐng)求。 首發(fā)于個(gè)人博客 目錄 跨域 簡單請(qǐng)求和復(fù)雜請(qǐng)求 服務(wù)端如何設(shè)置CORS @koa/cors是怎么實(shí)現(xiàn)的 跨域 為什么會(huì)有跨域問題? 這是瀏覽器的同源策略所造成的,同源策略限制了從同一個(gè)源加載的文檔或腳本如何與來自...

    loostudy 評(píng)論0 收藏0
  • 你不知道的CORS跨域資源共享

    摘要:同源策略禁止使用對(duì)象向不同源的服務(wù)器地址發(fā)起請(qǐng)求。借助于決解同源策略決解同源策略,新方案跨域資源共享這里講的重點(diǎn)跨域資源共享提供的標(biāo)準(zhǔn)跨域解決方案,是一個(gè)由瀏覽器共同遵循的一套控制策略,通過的來進(jìn)行交互主要通過后端來設(shè)置配置項(xiàng)。 了解下同源策略 源(origin)*:就是協(xié)議、域名和端口號(hào); 同源: 就是源相同,即協(xié)議、域名和端口完全相同; 同源策略:同源策略是瀏覽器的一個(gè)安全...

    Gu_Yan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<