面试官问:跨域请求如何携带cookie?

大家好,我是若‍川。持续组织了6个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列

本文来自经作者 @Ethan01 授权转载
原标题:面试题 -- 跨域请求如何携带cookie?
原链接:https://juejin.cn/post/7066420545327218725

前言

最近在参加面试找工作,陆陆续续的面了两三家。其中面试官问到了一个问题:如何解决跨域问题?我巴巴拉拉的一顿说,大概了说了四种方法,然后面试官紧接着又问:那跨域请求怎么携带cookie呢?(常规的面试套路,一般都会顺着你的回答往深了问)由于之前的项目都是同源的,不牵涉跨域访问,所以一时没有回答出来,后来研究了下,所以有了这篇文章。

阅读本文,你将学到:

1.学会`withCredentials`属性;
2.学会`axios`配置`withCredentials`;
3.学会设置`Access-Control-Allow-Origin`属性;
4.学会设置`Access-Control-Allow-Credentials`属性;
5.学会解决跨域请求携带源站cookie的问题;

一. 搭建一个跨域请求的环境

思路:

  1. 使用express搭建第一个服务A(http://localhost:8000),运行在8000端口上;

  2. A服务托管index.html(用于在前端页面发送网络请求)文件;

  3. A服务中写一个处理请求的路由,加载index.html页面时,种下cookie(这里种cookie为了在请求B服务时携带上);

  4. 使用express搭建第二个服务B(http://localhost:8003),运行在8003端口上;

  5. A服务托管的index.html页面去请求B服务,然后把cookie传过去;

先看下代码结构,相对比较的简单:

b6fdd7f0bffbbbce261ec65d112a6a8f.png
image.png

A服务的代码:

// src/app1.js
const express = require("express");
const app = express();// `index.html` 加载时会请求login接口
// 设置`cookie`
app.get("/login", (req, res) => {res.cookie("user", "jay", { maxAge: 2000000, httpOnly: true });res.json({ code: 0, message: "登录成功" });
});// 此接口是检测`cookie`是否设置成功,如果设置成功的话,浏览器会自动携带上`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`中发起的请求,默认的源就是`http://localhost:8000`
// 然后再去请求`http://localhost:8003`就会出现跨域了
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">发送同源请求</button><button id="cross-button">发送跨域请求</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);});// 发送同域请求button.onclick = function () {axios.get("http://localhost:8000/user", {}).then((res) => {console.log(res);});};// 发送跨域请求crossButton.onclick = function () {axios({method: "get",url: "http://localhost:8003/anotherService",}).then((res) => {console.log(res);});};</script></body>
</html>

B服务的代码:

// src/app2.js
const express = require("express");
const app = express();// 定义一个接口,index.html页面请求这个接口就是跨域(因为端口不同)
app.get("/anotherService", (req, res) => {res.json({ code: 0, msg: "这是8003端口返回的" });
});app.listen("8003", () => {console.log("app2 running at port 8003");
});

这个时候环境基本就搭建好了。

二、解决跨域携带cookie问题

首先我们先在A服务的index.html页面中得到一个cookie,运行A服务:

npm install express -D
node src/app1.js

然后打开http://localhost:8000/static/index.html: 没有问题的话,页面长这样:

077a96c00b1d19a71ea33c721b2d9f8e.png
image.png

这个时候F12打开控制台:可以看到发送了一个login请求,并且设置了 cookie,也可以选择浏览器控制台的Application页签,选中cookie,可以看到cookie的信息:

964a9e22f4575585b81fdde019e66133.png
image.png
b03fc6fd2d152c250458cafb9c581f91.png
image.png

然后我们点击页面上的发送同源请求按钮,可以看到发送了一个 user 请求,并且已经携带上了 cookie:

a61edf597df1057b1e50bc41a6e249d2.png
image.png

接下来刺激的画面来了,我们点击 发送跨域请求 按钮,出现了跨域请求的报错:

23cb923f9d231b4db1d464b69c53ce68.png
image.png

重点:接下来开始解决跨域携带 cookie 问题:

1. 在前端请求的时候设置 request 对象的属性 withCredentials 为 true;

什么是withCredentials

XMLHttpRequest.withCredentials 属性是一个Boolean类型,它指示了是否该使用类似 cookies,authorization headers(头部授权)或者 TLS 客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求。在同一个站点下使用withCredentials属性是无效的。

如果在发送来自其他域的 XMLHttpRequest 请求之前,未设置withCredentials  为 true,那么就不能为它自己的域设置 cookie 值。而通过设置withCredentials  为 true 获得的第三方 cookies,将会依旧享受同源策略,因此不能被通过document.cookie或者从头部相应请求的脚本等访问。

// 修改跨域请求的代码
crossButton.onclick = function () {axios({withCredentials: true, // ++ 新增method: "get",url: "http://localhost:8003/anotherService",}).then((res) => {console.log(res);});
};

这个时候再去发送一个跨域请求,你会发现依旧报错,但是我们仔细看下报错,意思是需要设置 header 的Access-Control-Allow-Origin属性:

79003ce28b9b2f5a91ba6bdd64b81b0e.png
image.png

2. 在服务端设置Access-Control-Allow-Origin

我们修改B(app2.js)服务的代码:

// 在所有路由前增加,可以拦截所有请求
app.all("*", (req, res, next) => {res.header("Access-Control-Allow-Origin", "http://localhost:8000");next();
});

修改完之后再次发送一个跨域请求,你会发现,又报错了(接近崩溃),但是跟之前报的错不一样了,意思大概就是Access-Control-Allow-Credentials这个属性应该设置为true,但是显示得到的是个''

da1b0b487c2786d083b88b5ec4c7ebb9.png
image.png

3. 在服务端设置Access-Control-Allow-Credentials

再次修改 B 服务的代码(每次修改后需要重新运行):

// 在所有路由前增加,可以拦截所有请求
app.all("*", (req, res, next) => {res.header("Access-Control-Allow-Origin", "http://localhost:8000");res.header("Access-Control-Allow-Credentials", "true"); // ++ 新增next();
});

再发送一个跨域请求:

33dd0426ec73c87cdacfe1f9d226d18b.png
image.png
33b54ce54a4e05f3b59e8f8ac9436bc3.png
image.png

可以看到,这个跨域请求已经请求成功并且返回数据了!而且也携带了A服务的cookie,这个时候已经大功告成了。

三、总结

  1. 前端请求时在request对象中配置"withCredentials": true

  2. 服务端在responseheader中配置"Access-Control-Allow-Origin", "http://xxx:${port}";

  3. 服务端在responseheader中配置"Access-Control-Allow-Credentials", "true"

如果看完这篇文章能够帮助到你,请给个赞哦~

0806c701afd6b050f071036f6eeb322f.gif

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》20余篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结。
同时,最近组织了源码共读活动,帮助3000+前端人学会看源码。公众号愿景:帮助5年内前端人走向前列。

44a6522d13085043d4b504b63b9b5f62.png

识别方二维码加我微信、拉你进源码共读

今日话题

略。分享、收藏、点赞、在看我的文章就是对我最大的支持~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/274860.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ux设计中的各种地图_移动应用程序设计中的常见UX错误

ux设计中的各种地图Have you ever tried a new app, only to realize you have no idea how to use it?您是否曾经尝试过一个新的应用程序&#xff0c;却发现自己不知道如何使用它&#xff1f; Few things can transport a person from calm and happy, to frustrated and an…

如何使用 Node 后端创建 React 应用程序:完整指南

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列React…

工业仪器仪表 界面设计_如何设计时尚的仪表板界面

工业仪器仪表 界面设计重点 (Top highlight)Welcome to the second step by step UI guide. Since you really liked my first article on “How to achieve Friendly, Lightweight UI”, I decided to make another one in a similar manner. Please note, that this is not a…

给3月要跳槽的前端提个醒!不了解微前端就别去面试了,不然……

在后端架构发展史上&#xff0c;如果要找一个低耦合高内聚架构模式的典范&#xff0c;微服务当仁不让。在互联网业务急速扩张的背景下&#xff0c;微服务架构解决了后端服务中的“重”&#xff0c;让每个服务都能够独立部署、独立扩展&#xff0c;每个服务都具有稳固的模块边界…

ui和ux的区别_UI和UX之间的区别

ui和ux的区别You’ve probably heard a lot of self-proclaimed “UX/UI” designers out there, the word “UI” thrown around endlessly at Apple keynotes, or tech startups saying “we need to fix the UX here and the UX there.”Ÿouve可能听说过很多自称“UX / UI”…

用JS轻松实现一个录音、录像、录屏工具库

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列前言最…

文本字段和表单设计-UI组件系列

重点 (Top highlight)Forms have existed for a significant amount of time, greatly simplifying the task of drafting complaints and various other legal pleadings. With the advance of information and its processing, means to gather the data are also evolving. …

WCF 第四章 绑定 netMsmqBinding

MSMQ 为使用队列创建分布式应用程序提供支持。WCF支持将MSMQ队列作为netMsmqBinding绑定的底层传输协议的通信。 netMsmqBinding绑定允许客户端直接把消息提交到一个队列中同时服务端从队列中读取消息。客户端和服务端之间没有直接通信过程&#xff1b;因此&#xff0c;通信本 …

React 18 RC 版本发布啦,生产环境用起来!

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列今天给…

阿拉伯语排版设计_针对说阿拉伯语的用户的测试和设计

阿拉伯语排版设计Let me start off with some data to put things into perspective “Why?”让我从一些数据入手&#xff0c;以透视“为什么&#xff1f;”的观点。 Arabic is the 5th most spoken language worldwide, with 420 million speakers, and is an official lang…

SVN:“SVN”不是内部命令,解决方法

1、安装完TortoiseSVN-1.6.16.21511-x64-svn-1.6.17.msi 2、在运行窗口cmd---svn&#xff0c;提示&#xff1a; “SVN” 不是内部命令 郁闷&#xff0c;小有纠结 解决方法&#xff1a;安装Slik-Subversion-1.6.17-x64.msi 命令行窗口关闭&#xff0c;再次打开命令行窗口&#x…

7个月,4000+人,500+源码笔记,诚邀你参加源码共读~

大家好&#xff0c;我是若川。按照从易到难的顺序&#xff0c;前面几期&#xff08;比如&#xff1a;validate-npm-package-name、axios工具函数&#xff09;很多都只需要花2-3小时就能看完&#xff0c;并写好笔记。但收获确实很大。开阔视野、查漏补缺、升职加薪。已经有400笔…

火焰和烟雾的训练图像数据集_游戏开发者是烟雾和镜子的大师

火焰和烟雾的训练图像数据集Video games are incredible. They transport us to new worlds, allow us to partake in otherwise impossible situations, and empower us in our every day lives. Games can make us feel like a part of something bigger than ourselves, per…

平衡树SPLAY

一个比线段树代码还要又臭又长的数据结构&#xff0c;各式各样的函数&#xff0c;咱也不知道别人怎么记住的&#xff0c;咱也不敢问 SPLAY的性质 1.某个节点的左子树全部小于此节点&#xff0c;右子树全部大于此节点 2.中序遍历splay输出的序列是按从小到大的顺序 &#xff08;…

为支持两个语言版本,我基于谷歌翻译API写了一款自动翻译的 webpack 插件

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列本文来…

全球 化 化_全球化设计

全球 化 化重点 (Top highlight)Designing for a global audience can feel daunting. Do you localize your product? Or, do you internationalize your product? And what does that even entail?为全球观众设计可能会令人生畏。 您是否将产品本地化&#xff1f; 还是您将…

springMVC_数据的处理过程

1、DispatcherServlet&#xff1a;作为前端控制器&#xff0c;负责分发客户的请求到 Controller 其在web.xml中的配置如下&#xff1a; <servlet><servlet-name>dispatcherServlert</servlet-name><servlet-class>org.springframework.web.servlet.Dis…

JavaScript 新增两个原始数据类型

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列JavaS…

axure低保真原型_如何在Google表格中创建低保真原型

axure低保真原型Google Sheets is a spreadsheet, just like Microsoft Excel.Google表格是一个电子表格&#xff0c;就像Microsoft Excel一样。 Most people associate it with calculating numbers. But Google Sheets is actually great for organizing your ideas, making…

Lerna 运行流程剖析

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列Lerna…