前端遇到302处理方式以及设置第三方Cookie研究

这篇具有很好参考价值的文章主要介绍了前端遇到302处理方式以及设置第三方Cookie研究。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前端遇到302处理方式以及设置第三方Cookie研究

1、如何解决后端302重定向问题

背景:由于认证中心网关检测到用户是未登录态情况下的话,会将用户重定向到认证中心的登录页。

​ 此时,假如是使用Oauth2协议,登录成功后,前端需要带着登录成功的信息(jwt),访问/Oauth2/1/authorize接口,此时该接口将会重定向回redirect_uri的地址,这个时候的重点在于如何访问/Oauth2/1/authorize接口

我们列举一下几种请求方式:

  1. Ajax
  2. Fetch
  3. Location.href
  4. Form表单
  5. Nvigator.sendBeacon
技术 特点 是否可用
Ajax(XMLHttpRequest 不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容,捕获不到302状态码,并且假如后端响应头的Location返回的路径与Ajax的Referer不一致的话,会产生跨域报错。 ×
Fetch 针对 302 的情况,其实 fetch 有个特殊的配置叫 redirect,可以捕获302的部分内容。但是非常可惜的是,目前 response 的内容非常有限,仅能捕获到该接口访问是否存在302,捕获不到302的具体跳转路径,并且也不能跟随跳转。 ×
Location.href 浏览器地址直接跳转接口,默认采用Get请求,不存在跨域问题,浏览器也可以直接跟随后端产生的302重定向。
Form表单 通过刷新整个页面进行访问请求,可使用Get/Post方法,也可以跟随后端进行的302跳转,缺点是需要新建一个表单,操作比较复杂。
Nvigator.sendBeacon navigator.sendBeacon() 方法可用于通过 HTTP POST 将少量数据异步传输到 Web 服务器。同时避免了用传统技术(如:XMLHttpRequest)发送分析数据的一些问题。缺点是仅支持POST请求,以及是异步操作,也不跟随后端302。

根据以上方式做一个测试:

我们做一个302重定向的接口,重定向的路径是分别为http://localhost:3000/login和https://www.baidu.com,客户端的域名为localhost,情况如下图:

前端302,前端,服务器,运维,http,react.js,spring boot

假如采用常用的Ajax,例如Axios或者Fetch,前端代码以及效果如下:

1、Axios:当点击按钮时候,调用/redirectTo接口,后端返回302重定向,此时我们可以看到,重定向后的地址并不是按照预期在浏览器上跳转,而是重新用XHR请求重定向之后的地址,此时由于接口请求头的Referer为localhost:3000与RequestURL:https:www.baidu.com存在跨域问题,故报错。

前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot

  • 那假如后端返回重定向的地址不存在跨域问题呢(此时和客户端同域)?

​ 此时虽然不存在跨域问题了,但是重定向后的地址因为是使用XHR访问的,然而你客户端并没有开启Servlet等服务,故接口会返回404NotFound。
前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot

  • 综上所述,使用Ajax处理302是行不通的。
2、采用Fetch,网上对于fetch众说纷纭,经测试,fetch也不能跟随302跳转页面,会将请求后的报文体返回回来。

前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot

3、使用Location.href,无论重定向后的地址是否跨域,均可以成功重定向。

前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot

4、使用form表单做302跳转,也是可以成功的,但是需要创建一个虚拟节点,处理起来较为复杂。

前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot

5、Nvigator.sendBeacon,由于该方法必须采用Post,故更改一下后端代码。虽然使用该方法没有跨域问题,但是由于是异步方法,并不会让浏览器跟随302操作。

前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot
前端302,前端,服务器,运维,http,react.js,spring boot

总结:使用Location.href直接访问接口

​ 上述五种方式,Ajax和Fetch皆是异步请求,不能跟随浏览器302的操作,并且还获取不到接口返回的Location等信息,所以不采用。Form表单可以使用,功能也较为全面,但是实现方式较为复杂,且Form表单通常用于表单内容提交,与场景语义不符,故Pass**。Location.href的方式即以Get请求直接使用浏览器访问该接口,参数携带方便,也能跟随重定向操作,故采用。**

附上代码:

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}>测试Axios重定向</button>
      <button onClick={useFetchSetRedirect}>测试Fetch重定向</button>
      <button onClick={useLocationRedirect}>测试location重定向</button>
      <button onClick={useFormData}>测试Form表单重定向</button>
      <button onClick={useSendBeacon}>测试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、子系统(接入认证中心的系统)如何接入认证中心,获取登录态?

背景:由于子系统和认证中心是不同的系统,在认证中心登录成功后重定向回子系统的过程中,如何得知已登录的登录态呢?

​ 此时我们在重定向的过程中,需要传递信息给其他系统,仅有三种方式(据我所知):

  1. ​ 浏览器地址栏携带

  2. ​ Cookie

  3. ​ Window.postMessage

    实现方式 特点 是否可用
    浏览器地址栏携带 优点:操作方便,无同域限制 ; 缺点:信息完全暴露在地址栏,安全性不高
    Cookie 优点:在设置Cookie的时候可以通过Domain、Path、SameSite等字段,将Cookie设置在需要获取的应用上 ,安全性以及准确性较高; 缺点:遵循浏览器的同源限制,设置的Cookie仅在本域名或者子域名下共享。
    Window.postMessage 是一种浏览器提供的跨域传输信息方式,在认证中心完成登录操作,拿到Token的话,可以使用该方式传输信息。但是与使用场景不符,故Pass掉 ×
总结: 浏览器地址栏携带和Cookie均可以完成302后传递信息(assess-token或者code)的操作,其中各有优缺点,应根据项目需要以及具体情况具体采用不同的方式。同域建议采用Cookie,不同域推荐采用浏览器地址栏携带。
  • 子系统与认证中心同域

    ​ 采用Cookie方式可以较为简单地实现单点登录,设置Cookie(access-token)到具体的域(Domain),通过Path去限制相应的系统,这样可以发挥认证中心实现单点登录的效果。但是浏览器必须把Cookie打开,以及应对Cookie具体设置对应的条件,以防其他系统通过CSRF等手段,获取到用户信息。

  • 子系统与认证中心跨域

​ 建议采用浏览器地址栏携传递信息,这个时候考虑到安全问题,不应该采用明文的形势将access-token放到地址栏,而是将重定向后携带的code通过地址栏传输回去子系统,然后子系统通过这个code调用接口获取access-token(采用空白页的方式)。

3、拓展:302跳转如何SetCookie到对应的系统。

背景:出现在本地联调的情况,后端设置重定向到对应的系统,并SetCookie到开发环境,设置Domain为开发环境的ip/域名,但是发现Cookie并未设置上。

​ 故排查原因,发现是因为重定向的接口的请求头中Host与后端设置的Domain不一致,Cookie被屏蔽掉了。报错如下图:

前端302,前端,服务器,运维,http,react.js,spring boot

为此我做了个测试,模拟设置Cookie到百度的网站上:

  • 首先设置Host文件(127.0.0.1 test.baidu.com),模拟百度的域名到本机ip;

  • 然后在后端代码重定向到www.baidu.com,同时设置cookie到baidu.com这个域名上。

     @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);
        }
    
  • 重点:前端调用该后端接口时,不可以用localhost调用,而是用test.baidu.com这个域名调用,如下:

     const testThirdCookie = ()=>{
        window.location.href = "http://test.baidu.com:8080/setCookieRedirect"
      }
    

最后成功设置Cookie到百度上,效果如下:

前端302,前端,服务器,运维,http,react.js,spring boot

总结:关键就是请求头的host与设置的Domain对象域名得一致,或者父级域名包括子级域名即可。
   const testThirdCookie = ()=>{
      window.location.href = "http://test.baidu.com:8080/setCookieRedirect"
    }

最后成功设置Cookie到百度上,效果如下:前端302,前端,服务器,运维,http,react.js,spring boot文章来源地址https://www.toymoban.com/news/detail-667564.html

总结:关键就是请求头的host与设置的Domain对象域名得一直,或者父级域名包括子级域名即可。

到了这里,关于前端遇到302处理方式以及设置第三方Cookie研究的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python 安装第三方库时遇到的问题(pip版本低、需更新)

    提示问题: 但是加载一会后又显示下载失败。 可能存在问题:pip下载的第三方库是国外的,不支持断点传输,网络很慢。当pip是下载到一半时才报的错,大概率可能是网络的问题。因此使用国内镜像pypi源,可实现快速下载。 解决方法:在要下载的库后面加上国内源,即可快

    2024年02月03日
    浏览(39)
  • java对接第三方接口的三种方式

    在日常工作中,经常需要跟第三方系统对接,我们做为客户端,调用他们的接口进行业务处理,常用的几种调用方式有: 1.原生的Java.net.HttpURLConnection(jdk); 2.再次封装的HttpClient、CloseableHttpClient(Apache); 3.Spring提供的RestTemplate; 当然还有其他工具类进行封装的接口,比

    2024年04月28日
    浏览(57)
  • Android Studio引用第三方库的方式

    title: 大小端详解 date: 2023-06-06 21:01:24 comments: true #是否可评论 toc: true #是否显示文章目录 categories: #分类 - gradle - android studio tags: #标签 - gradle - android studio summary: android stduio 导入第三方库方式 这里描述的第三方库文件格式指的是 so aar so库介绍一种方法 Aar介绍两种方法 libs目录

    2024年02月08日
    浏览(55)
  • Java调用第三方http接口的常用方式

    前言 一、通过JDK网络类Java.net.HttpURLConnection 二、通过apache common封装好的HttpClient 三、通过Spring的RestTemplate 总结 今天项目需要接口互相调用,就看了一下这几个调用的方式 通过java.net包下的原生java.api提供的http请求 使用步骤: 通过统一的资源定位器(java.net.URL)获取连接器(java.

    2024年02月08日
    浏览(66)
  • Spring xml 方式整合mybatis 第三方框架

    MyBatis提供了mybatis-spring.jar专门用于两大框架的整合。 ①:第一步: 导入MyBatis整合Spring的相关坐标; ②:第二步: 编写Mapper和Mapper.xml ③:第三步: 配置SqlSessionFactoryBean和MapperScannerConfigurer ④:第四步: 编写测试代码

    2024年02月13日
    浏览(60)
  • python第三方库下载与更改方式(在命令行下载)

    寻找点击需要的库: https://www.lfd.uci.edu/~gohlke/pythonlibs         第一种普通方式:在命令行中输入“pip install 库名“,比如:         第二种急速方式:在命令行中输入“pip install -i https://pypi.douban.com/simple/库名” ,比如:          在命令行中输入“pip uninstall 库名”

    2024年02月16日
    浏览(35)
  • 第三方组件及计算属性传参的问题解决方式

    唉,好想玩滋嘣。 表格数据某一列需要用的计算属性时,模板中使用计算属性 fullName 就会直接调用 fullName 函数,而在模板中 fullName(item) 相当于 fullName()(item) ,此处为函数柯里化。 封装好的组件的事件回调函数想要传其它参数,事件的回调直接写 :before-upload=\\\"beforeUpload(\\\'a\\\')

    2024年02月05日
    浏览(55)
  • python第三方库 ~ Reportlab 设置页面边距

    SimpleDocTemplate 继承 BaseDocTemplate BaseDocTemplate 包含 leftMargin 、 topMargin 单位都是inch, 修改这两个, 右边距和下边距在 doc.build 的时候会自动计算

    2024年02月11日
    浏览(51)
  • python--pip换源以及第三方模块安装

    pip install django 国外地址,速度慢 pip install django -i http://pypi.douban.com/simple/ 统一修改,以后都走豆瓣源 配置步骤: 1 去‘C:Usersxxxx’路径,在地址栏输入 %APPDATA% 敲回车,进入‘C:UsersxxxxAppDataRoaming’目录 2 新建 pip 文件夹并在文件夹新建pip.ini文件 3 新增 pip.ini 配置文件内

    2023年04月08日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包