前端遇到302重定向問(wèn)題處理方式及設(shè)置第三方Cookie研究
前端遇到302處理方式以及設(shè)置第三方Cookie研究
1、如何解決后端302重定向問(wèn)題
背景:由于認(rèn)證中心網(wǎng)關(guān)檢測(cè)到用戶(hù)是未登錄態(tài)情況下的話(huà),會(huì)將用戶(hù)重定向到認(rèn)證中心的登錄頁(yè)。
? 此時(shí),假如是使用Oauth2協(xié)議,登錄成功后,前端需要帶著登錄成功的信息(jwt),訪(fǎng)問(wèn)/Oauth2/1/authorize接口,此時(shí)該接口將會(huì)重定向回redirect_uri的地址,這個(gè)時(shí)候的重點(diǎn)在于如何訪(fǎng)問(wèn)/Oauth2/1/authorize接口。
我們列舉一下幾種請(qǐng)求方式:
- Ajax
- Fetch
- Location.href
- Form表單
- Nvigator.sendBeacon
| 技術(shù) | 特點(diǎn) | 是否可用 |
|---|---|---|
| Ajax(XMLHttpRequest ) | 不重新加載整個(gè)頁(yè)面的情況下,可以與服務(wù)器交換數(shù)據(jù)并更新部分網(wǎng)頁(yè)內(nèi)容,捕獲不到302狀態(tài)碼,并且假如后端響應(yīng)頭的Location返回的路徑與Ajax的Referer不一致的話(huà),會(huì)產(chǎn)生跨域報(bào)錯(cuò)。 | × |
| Fetch | 針對(duì) 302 的情況,其實(shí) fetch 有個(gè)特殊的配置叫 redirect,可以捕獲302的部分內(nèi)容。但是非常可惜的是,目前 response 的內(nèi)容非常有限,僅能捕獲到該接口訪(fǎng)問(wèn)是否存在302,捕獲不到302的具體跳轉(zhuǎn)路徑,并且也不能跟隨跳轉(zhuǎn)。 | × |
| Location.href | 瀏覽器地址直接跳轉(zhuǎn)接口,默認(rèn)采用Get請(qǐng)求,不存在跨域問(wèn)題,瀏覽器也可以直接跟隨后端產(chǎn)生的302重定向。 | √ |
| Form表單 | 通過(guò)刷新整個(gè)頁(yè)面進(jìn)行訪(fǎng)問(wèn)請(qǐng)求,可使用Get/Post方法,也可以跟隨后端進(jìn)行的302跳轉(zhuǎn),缺點(diǎn)是需要新建一個(gè)表單,操作比較復(fù)雜。 | √ |
| Nvigator.sendBeacon | navigator.sendBeacon() 方法可用于通過(guò) HTTP POST 將少量數(shù)據(jù)異步傳輸?shù)?Web 服務(wù)器。同時(shí)避免了用傳統(tǒng)技術(shù)(如:XMLHttpRequest)發(fā)送分析數(shù)據(jù)的一些問(wèn)題。缺點(diǎn)是僅支持POST請(qǐng)求,以及是異步操作,也不跟隨后端302。 | √ |
根據(jù)以上方式做一個(gè)測(cè)試:
我們做一個(gè)302重定向的接口,重定向的路徑是分別為http://localhost:3000/login和https://www.baidu.com,客戶(hù)端的域名為localhost,情況如下圖:

假如采用常用的Ajax,例如Axios或者Fetch,前端代碼以及效果如下:
1、Axios:當(dāng)點(diǎn)擊按鈕時(shí)候,調(diào)用/redirectTo接口,后端返回302重定向,此時(shí)我們可以看到,重定向后的地址并不是按照預(yù)期在瀏覽器上跳轉(zhuǎn),而是重新用XHR請(qǐng)求重定向之后的地址,此時(shí)由于接口請(qǐng)求頭的Referer為localhost:3000與RequestURL:https:www.baidu.com存在跨域問(wèn)題,故報(bào)錯(cuò)。



那假如后端返回重定向的地址不存在跨域問(wèn)題呢(此時(shí)和客戶(hù)端同域)?
此時(shí)雖然不存在跨域問(wèn)題了,但是重定向后的地址因?yàn)槭鞘褂肵HR訪(fǎng)問(wèn)的,然而你客戶(hù)端并沒(méi)有開(kāi)啟Servlet等服務(wù),故接口會(huì)返回404NotFound。



綜上所述,使用Ajax處理302是行不通的。
2、采用Fetch,網(wǎng)上對(duì)于fetch眾說(shuō)紛紜,經(jīng)測(cè)試,fetch也不能跟隨302跳轉(zhuǎn)頁(yè)面,會(huì)將請(qǐng)求后的報(bào)文體返回回來(lái)。



3、使用Location.href,無(wú)論重定向后的地址是否跨域,均可以成功重定向。



4、使用form表單做302跳轉(zhuǎn),也是可以成功的,但是需要?jiǎng)?chuàng)建一個(gè)虛擬節(jié)點(diǎn),處理起來(lái)較為復(fù)雜。



5、Nvigator.sendBeacon,由于該方法必須采用Post,故更改一下后端代碼。雖然使用該方法沒(méi)有跨域問(wèn)題,但是由于是異步方法,并不會(huì)讓瀏覽器跟隨302操作。



總結(jié):使用Location.href直接訪(fǎng)問(wèn)接口
上述五種方式,Ajax和Fetch皆是異步請(qǐng)求,不能跟隨瀏覽器302的操作,并且還獲取不到接口返回的Location等信息,所以不采用。Form表單可以使用,功能也較為全面,但是實(shí)現(xiàn)方式較為復(fù)雜,且Form表單通常用于表單內(nèi)容提交,與場(chǎng)景語(yǔ)義不符,故Pass**。Location.href的方式即以Get請(qǐng)求直接使用瀏覽器訪(fǎng)問(wèn)該接口,參數(shù)攜帶方便,也能跟隨重定向操作,故采用。**
附上代碼:
import serviceInstance from "../../services";
// const res = serviceInstance({
// url: "/redirectTo", //不用引入,直接在api后面接接口
// method: "get",
// data: {},
// });
// console.log(res);
function Home() {
const setRedirect = () => {
const res = serviceInstance({
url: "/redirectTo", //不用引入,直接在api后面接接口
method: "get",
data: {},
});
console.log(res);
};
const useFetchSetRedirect = () => {
const res = fetch("/redirectTo",{
method: "get",
redirect:'follow'
});
console.log(res);
};
const useLocationRedirect = () => {
window.location.href = "http://localhost:8080/redirectTo"
};
const useFormData = ()=>{
const form = document.createElement("form");
form.action = "http://localhost:8080/redirectTo";
document.getElementById("container").appendChild(form);
form.submit();
document.getElementById("container").removeChild(form);
}
const useSendBeacon = ()=>{
navigator.sendBeacon("http://localhost:8080/redirectToPost")
}
return (
<div id="container">
<button onClick={setRedirect}>測(cè)試Axios重定向</button>
<button onClick={useFetchSetRedirect}>測(cè)試Fetch重定向</button>
<button onClick={useLocationRedirect}>測(cè)試location重定向</button>
<button onClick={useFormData}>測(cè)試Form表單重定向</button>
<button onClick={useSendBeacon}>測(cè)試SendBeacon重定向</button>
</div>
);
}
export default Home;package com.xuan.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
public class TestController {
@GetMapping("/redirectTo")
void testRedirect(HttpServletResponse response) throws IOException {
String testUrl = "https://www.baidu.com";
// String testUrl2 = "http://localhost:3000/login";
response.sendRedirect(testUrl);
}
@PostMapping ("/redirectToPost")
void testRedirectPost(HttpServletResponse response) throws IOException {
String testUrl = "https://www.baidu.com";
// String testUrl2 = "http://localhost:3000/login";
response.sendRedirect(testUrl);
}
}2、子系統(tǒng)(接入認(rèn)證中心的系統(tǒng))如何接入認(rèn)證中心,獲取登錄態(tài)?
背景:由于子系統(tǒng)和認(rèn)證中心是不同的系統(tǒng),在認(rèn)證中心登錄成功后重定向回子系統(tǒng)的過(guò)程中,如何得知已登錄的登錄態(tài)呢?
此時(shí)我們?cè)谥囟ㄏ虻倪^(guò)程中,需要傳遞信息給其他系統(tǒng),僅有三種方式(據(jù)我所知):
瀏覽器地址欄攜帶
Cookie
Window.postMessage
實(shí)現(xiàn)方式 特點(diǎn) 是否可用 瀏覽器地址欄攜帶 優(yōu)點(diǎn):操作方便,無(wú)同域限制 ; 缺點(diǎn):信息完全暴露在地址欄,安全性不高 √ Cookie 優(yōu)點(diǎn):在設(shè)置Cookie的時(shí)候可以通過(guò)Domain、Path、SameSite等字段,將Cookie設(shè)置在需要獲取的應(yīng)用上 ,安全性以及準(zhǔn)確性較高; 缺點(diǎn):遵循瀏覽器的同源限制,設(shè)置的Cookie僅在本域名或者子域名下共享。 √ Window.postMessage 是一種瀏覽器提供的跨域傳輸信息方式,在認(rèn)證中心完成登錄操作,拿到Token的話(huà),可以使用該方式傳輸信息。但是與使用場(chǎng)景不符,故Pass掉 ×
總結(jié): 瀏覽器地址欄攜帶和Cookie均可以完成302后傳遞信息(assess-token或者code)的操作,其中各有優(yōu)缺點(diǎn),應(yīng)根據(jù)項(xiàng)目需要以及具體情況具體采用不同的方式。同域建議采用Cookie,不同域推薦采用瀏覽器地址欄攜帶。
- 子系統(tǒng)與認(rèn)證中心同域
采用Cookie方式可以較為簡(jiǎn)單地實(shí)現(xiàn)單點(diǎn)登錄,設(shè)置Cookie(access-token)到具體的域(Domain),通過(guò)Path去限制相應(yīng)的系統(tǒng),這樣可以發(fā)揮認(rèn)證中心實(shí)現(xiàn)單點(diǎn)登錄的效果。但是瀏覽器必須把Cookie打開(kāi),以及應(yīng)對(duì)Cookie具體設(shè)置對(duì)應(yīng)的條件,以防其他系統(tǒng)通過(guò)CSRF等手段,獲取到用戶(hù)信息。
- 子系統(tǒng)與認(rèn)證中心跨域
建議采用瀏覽器地址欄攜傳遞信息,這個(gè)時(shí)候考慮到安全問(wèn)題,不應(yīng)該采用明文的形勢(shì)將access-token放到地址欄,而是將重定向后攜帶的code通過(guò)地址欄傳輸回去子系統(tǒng),然后子系統(tǒng)通過(guò)這個(gè)code調(diào)用接口獲取access-token(采用空白頁(yè)的方式)。
3、拓展:302跳轉(zhuǎn)如何SetCookie到對(duì)應(yīng)的系統(tǒng)。
背景:出現(xiàn)在本地聯(lián)調(diào)的情況,后端設(shè)置重定向到對(duì)應(yīng)的系統(tǒng),并SetCookie到開(kāi)發(fā)環(huán)境,設(shè)置Domain為開(kāi)發(fā)環(huán)境的ip/域名,但是發(fā)現(xiàn)Cookie并未設(shè)置上。
故排查原因,發(fā)現(xiàn)是因?yàn)橹囟ㄏ虻慕涌诘?strong>請(qǐng)求頭中Host與后端設(shè)置的Domain不一致,Cookie被屏蔽掉了。報(bào)錯(cuò)如下圖:

為此我做了個(gè)測(cè)試,模擬設(shè)置Cookie到百度的網(wǎng)站上:
首先設(shè)置Host文件(127.0.0.1 test.baidu.com),模擬百度的域名到本機(jī)ip;
然后在后端代碼重定向到www.baidu.com,同時(shí)設(shè)置cookie到baidu.com這個(gè)域名上。
@GetMapping("/setCookieRedirect")
void testCookieRedirect(HttpServletResponse response) throws IOException {
String testUrl = "http://baidu.com";
Cookie cookie = new Cookie("testCookie","test");
cookie.setDomain("baidu.com");
cookie.setMaxAge(43200);
cookie.setSecure(false);
cookie.setHttpOnly(false);
response.addCookie(cookie);
response.sendRedirect(testUrl);
}重點(diǎn):前端調(diào)用該后端接口時(shí),不可以用localhost調(diào)用,而是用test.baidu.com這個(gè)域名調(diào)用,如下:
const testThirdCookie = ()=>{
window.location.
}最后成功設(shè)置Cookie到百度上,效果如下:

總結(jié):關(guān)鍵就是請(qǐng)求頭的host與設(shè)置的Domain對(duì)象域名得一致,或者父級(jí)域名包括子級(jí)域名即可。
const testThirdCookie = ()=>{
window.location.
}最后成功設(shè)置Cookie到百度上,效果如下:

總結(jié):關(guān)鍵就是請(qǐng)求頭的host與設(shè)置的Domain對(duì)象域名得一直,或者父級(jí)域名包括子級(jí)域名即可。
總結(jié)
到此這篇關(guān)于前端遇到302重定向問(wèn)題處理方式及設(shè)置第三方Cookie研究的文章就介紹到這了,更多相關(guān)前端302處理及設(shè)置第三方Cookie內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VS2019 自定義項(xiàng)目模板的實(shí)現(xiàn)方法
這篇文章主要介紹了VS2019 自定義項(xiàng)目模板的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
git工作區(qū)暫存區(qū)與版本庫(kù)基本理解及提交流程全解
這篇文章主要為大家介紹了git工作區(qū)暫存區(qū)與版本庫(kù)基本理解及提交流程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-04-04
HTTP提交方式之PUT詳細(xì)介紹及POST和PUT的區(qū)別
這篇文章主要介紹了HTTP提交方式之PUT詳細(xì)介紹及POST和PUT的區(qū)別,本文簡(jiǎn)潔易懂,需要的朋友可以參考下2014-07-07
如果你有這33種癥狀了請(qǐng)離開(kāi)電腦去走走吧!
這篇文章主要介紹了如果你有這33種癥狀了請(qǐng)離開(kāi)電腦去走走吧!本文是關(guān)注程序員、上班族身心健康的文章,需要的朋友可以參考下2014-09-09
MobaXterm的安裝和使用及問(wèn)題小結(jié)
MobaXterm是一款全能的終端連接工具,支持SSH連接,支持FTP、串口等協(xié)議。接下來(lái)通過(guò)本文給大家分享MobaXterm的安裝和使用及遇到的問(wèn)題解決方法,感興趣的朋友跟隨小編一起看看吧2021-05-05
DeepSeek部署之GPU監(jiān)控指標(biāo)接入Prometheus的過(guò)程
文章介紹了如何在GPU主機(jī)上部署DeepSeek大模型,并使用GPU資源加速推理計(jì)算,通過(guò)監(jiān)控主機(jī)GPU的顯存使用情況等指標(biāo),可以更好地進(jìn)行運(yùn)維和優(yōu)化,感興趣的朋友跟隨小編一起看看吧2025-02-02
申請(qǐng)Jetbrains系列軟件無(wú)限期免費(fèi)用的方法
這篇文章主要介紹了如何申請(qǐng)Jetbrains系列軟件無(wú)限期免費(fèi)用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09

