面试官问:跨域请求如何携带cookie?
大家好,我是若?川。持續(xù)組織了6個(gè)月源碼共讀活動(dòng),感興趣的可以點(diǎn)此加我微信 ruochuan12?參與,每周大家一起學(xué)習(xí)200行左右的源碼,共同進(jìn)步。同時(shí)極力推薦訂閱我寫的《學(xué)習(xí)源碼整體架構(gòu)系列》?包含20余篇源碼文章。歷史面試系列
本文來自經(jīng)作者 @Ethan01 授權(quán)轉(zhuǎn)載
原標(biāo)題:面試題 -- 跨域請(qǐng)求如何攜帶cookie?
原鏈接:https://juejin.cn/post/7066420545327218725
前言
最近在參加面試找工作,陸陸續(xù)續(xù)的面了兩三家。其中面試官問到了一個(gè)問題:如何解決跨域問題?我巴巴拉拉的一頓說,大概了說了四種方法,然后面試官緊接著又問:那跨域請(qǐng)求怎么攜帶cookie呢?(常規(guī)的面試套路,一般都會(huì)順著你的回答往深了問)由于之前的項(xiàng)目都是同源的,不牽涉跨域訪問,所以一時(shí)沒有回答出來,后來研究了下,所以有了這篇文章。
閱讀本文,你將學(xué)到:
1.學(xué)會(huì)`withCredentials`屬性; 2.學(xué)會(huì)`axios`配置`withCredentials`; 3.學(xué)會(huì)設(shè)置`Access-Control-Allow-Origin`屬性; 4.學(xué)會(huì)設(shè)置`Access-Control-Allow-Credentials`屬性; 5.學(xué)會(huì)解決跨域請(qǐng)求攜帶源站cookie的問題;一. 搭建一個(gè)跨域請(qǐng)求的環(huán)境
思路:
使用express搭建第一個(gè)服務(wù)A(http://localhost:8000),運(yùn)行在8000端口上;
A服務(wù)托管index.html(用于在前端頁面發(fā)送網(wǎng)絡(luò)請(qǐng)求)文件;
在A服務(wù)中寫一個(gè)處理請(qǐng)求的路由,加載index.html頁面時(shí),種下cookie(這里種cookie為了在請(qǐng)求B服務(wù)時(shí)攜帶上);
使用express搭建第二個(gè)服務(wù)B(http://localhost:8003),運(yùn)行在8003端口上;
在A服務(wù)托管的index.html頁面去請(qǐng)求B服務(wù),然后把cookie傳過去;
先看下代碼結(jié)構(gòu),相對(duì)比較的簡單:
image.pngA服務(wù)的代碼:
//?src/app1.js const?express?=?require("express"); const?app?=?express();//?`index.html`?加載時(shí)會(huì)請(qǐng)求login接口 //?設(shè)置`cookie` app.get("/login",?(req,?res)?=>?{res.cookie("user",?"jay",?{?maxAge:?2000000,?httpOnly:?true?});res.json({?code:?0,?message:?"登錄成功"?}); });//?此接口是檢測`cookie`是否設(shè)置成功,如果設(shè)置成功的話,瀏覽器會(huì)自動(dòng)攜帶上`cookie` app.get("/user",?(req,?res)?=>?{//?req.headers.cookie:?user=jayconst?user?=?req.headers.cookie.split("=")[1];res.json({?code:?0,?user?}); });//?托管`index.html`頁面 //?這樣的話在`index.html`中發(fā)起的請(qǐng)求,默認(rèn)的源就是`http://localhost:8000` //?然后再去請(qǐng)求`http://localhost:8003`就會(huì)出現(xiàn)跨域了 app.use("/static",?express.static("public"));app.listen("8000",?()?=>?{console.log("app1?running?at?port?8000"); });index.html的代碼:
<!DOCTYPE?html> <html?lang="en"><head><meta?charset="UTF-8"?/><meta?http-equiv="X-UA-Compatible"?content="IE=edge"?/><meta?name="viewport"?content="width=device-width,?initial-scale=1.0"?/><title>Document</title></head><body><h2>this?is?index.html?at?port?8000</h2><button?id="button">發(fā)送同源請(qǐng)求</button><button?id="cross-button">發(fā)送跨域請(qǐng)求</button><script?src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>const?button?=?document.querySelector("#button");const?crossButton?=?document.querySelector("#cross-button");axios.get("http://localhost:8000/login",?{}).then((res)?=>?{console.log(res);});//?發(fā)送同域請(qǐng)求button.onclick?=?function?()?{axios.get("http://localhost:8000/user",?{}).then((res)?=>?{console.log(res);});};//?發(fā)送跨域請(qǐng)求crossButton.onclick?=?function?()?{axios({method:?"get",url:?"http://localhost:8003/anotherService",}).then((res)?=>?{console.log(res);});};</script></body> </html>B服務(wù)的代碼:
//?src/app2.js const?express?=?require("express"); const?app?=?express();//?定義一個(gè)接口,index.html頁面請(qǐng)求這個(gè)接口就是跨域(因?yàn)槎丝诓煌?#xff09; app.get("/anotherService",?(req,?res)?=>?{res.json({?code:?0,?msg:?"這是8003端口返回的"?}); });app.listen("8003",?()?=>?{console.log("app2?running?at?port?8003"); });這個(gè)時(shí)候環(huán)境基本就搭建好了。
二、解決跨域攜帶cookie問題
首先我們先在A服務(wù)的index.html頁面中得到一個(gè)cookie,運(yùn)行A服務(wù):
npm?install?express?-D node?src/app1.js然后打開http://localhost:8000/static/index.html: 沒有問題的話,頁面長這樣:
image.png這個(gè)時(shí)候F12打開控制臺(tái):可以看到發(fā)送了一個(gè)login請(qǐng)求,并且設(shè)置了 cookie,也可以選擇瀏覽器控制臺(tái)的Application頁簽,選中cookie,可以看到cookie的信息:
image.pngimage.png然后我們點(diǎn)擊頁面上的發(fā)送同源請(qǐng)求按鈕,可以看到發(fā)送了一個(gè) user 請(qǐng)求,并且已經(jīng)攜帶上了 cookie:
image.png接下來刺激的畫面來了,我們點(diǎn)擊 發(fā)送跨域請(qǐng)求 按鈕,出現(xiàn)了跨域請(qǐng)求的報(bào)錯(cuò):
image.png重點(diǎn):接下來開始解決跨域攜帶 cookie 問題:
1. 在前端請(qǐng)求的時(shí)候設(shè)置 request 對(duì)象的屬性 withCredentials 為 true;
什么是withCredentials?
XMLHttpRequest.withCredentials 屬性是一個(gè)Boolean類型,它指示了是否該使用類似 cookies,authorization headers(頭部授權(quán))或者 TLS 客戶端證書這一類資格證書來創(chuàng)建一個(gè)跨站點(diǎn)訪問控制(cross-site?Access-Control)請(qǐng)求。在同一個(gè)站點(diǎn)下使用withCredentials屬性是無效的。
如果在發(fā)送來自其他域的 XMLHttpRequest 請(qǐng)求之前,未設(shè)置withCredentials? 為 true,那么就不能為它自己的域設(shè)置 cookie 值。而通過設(shè)置withCredentials? 為 true 獲得的第三方 cookies,將會(huì)依舊享受同源策略,因此不能被通過document.cookie或者從頭部相應(yīng)請(qǐng)求的腳本等訪問。
//?修改跨域請(qǐng)求的代碼 crossButton.onclick?=?function?()?{axios({withCredentials:?true,?//?++?新增method:?"get",url:?"http://localhost:8003/anotherService",}).then((res)?=>?{console.log(res);}); };這個(gè)時(shí)候再去發(fā)送一個(gè)跨域請(qǐng)求,你會(huì)發(fā)現(xiàn)依舊報(bào)錯(cuò),但是我們仔細(xì)看下報(bào)錯(cuò),意思是需要設(shè)置 header 的Access-Control-Allow-Origin屬性:
image.png2. 在服務(wù)端設(shè)置Access-Control-Allow-Origin
我們修改B(app2.js)服務(wù)的代碼:
//?在所有路由前增加,可以攔截所有請(qǐng)求 app.all("*",?(req,?res,?next)?=>?{res.header("Access-Control-Allow-Origin",?"http://localhost:8000");next(); });修改完之后再次發(fā)送一個(gè)跨域請(qǐng)求,你會(huì)發(fā)現(xiàn),又報(bào)錯(cuò)了(接近崩潰),但是跟之前報(bào)的錯(cuò)不一樣了,意思大概就是Access-Control-Allow-Credentials這個(gè)屬性應(yīng)該設(shè)置為true,但是顯示得到的是個(gè)'':
image.png3. 在服務(wù)端設(shè)置Access-Control-Allow-Credentials
再次修改 B 服務(wù)的代碼(每次修改后需要重新運(yùn)行):
//?在所有路由前增加,可以攔截所有請(qǐng)求 app.all("*",?(req,?res,?next)?=>?{res.header("Access-Control-Allow-Origin",?"http://localhost:8000");res.header("Access-Control-Allow-Credentials",?"true");?//?++?新增next(); });再發(fā)送一個(gè)跨域請(qǐng)求:
image.pngimage.png可以看到,這個(gè)跨域請(qǐng)求已經(jīng)請(qǐng)求成功并且返回?cái)?shù)據(jù)了!而且也攜帶了A服務(wù)的cookie,這個(gè)時(shí)候已經(jīng)大功告成了。
三、總結(jié)
前端請(qǐng)求時(shí)在request對(duì)象中配置"withCredentials": true;
服務(wù)端在response的header中配置"Access-Control-Allow-Origin", "http://xxx:${port}";
服務(wù)端在response的header中配置"Access-Control-Allow-Credentials", "true"
如果看完這篇文章能夠幫助到你,請(qǐng)給個(gè)贊哦~
·················?若川簡介?·················
你好,我是若川,畢業(yè)于江西高校。現(xiàn)在是一名前端開發(fā)“工程師”。寫有《學(xué)習(xí)源碼整體架構(gòu)系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會(huì)寫一篇年度總結(jié),已經(jīng)寫了7篇,點(diǎn)擊查看年度總結(jié)。
同時(shí),最近組織了源碼共讀活動(dòng),幫助3000+前端人學(xué)會(huì)看源碼。公眾號(hào)愿景:幫助5年內(nèi)前端人走向前列。
識(shí)別上方二維碼加我微信、拉你進(jìn)源碼共讀群
今日話題
略。分享、收藏、點(diǎn)贊、在看我的文章就是對(duì)我最大的支持~
總結(jié)
以上是生活随笔為你收集整理的面试官问:跨域请求如何携带cookie?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [html] 什么是空元素?常用的空元
- 下一篇: CenterCrop图像裁剪原理