阅读视图

发现新文章,点击刷新页面。

前端真的需要懂算法吗?聊聊感受

image.png 在公司干了几年,带个小团队,零零总总也面试了上百个前端候选人了。说实话,有时候面完一天,感觉人都是麻的。

最让我头疼的是什么?就是“算法题”这个环节。

我经常遇到两种候选人。一种是一听算法题,就两手一摊,表情痛苦,说“哥,我天天写业务,真没准备这个”。另一种呢,正好相反,题目一出,眼睛一亮,不出三十秒,就把LeetCode上背得滚瓜烂熟的最优解,一字不差地敲了出来,然后一脸期待地看着我。

说实话,这两种,都不是我最想看到的。

这就引出了一个很多候选人都想问,但不敢问的问题:“你们这些面试官,到底怎么想的?你们明知道我们前端平时工作中,99%的时间都用不上这些,为什么非要折磨我们?”

今天,我就想站在桌子对面,跟大伙掏心窝子地聊聊,我们问算法题,到底图个啥。


首先,我得承认一件事:我们知道你工作中不怎么写算法

对,你没看错。

我心里门儿清,我团队里的小伙伴们,每天的工作是跟产品经理“吵架”,是跟UI设计师对像素,是封装React/Vue组件,是处理浏览器兼容性,是调CSS。我招你进来,也不是为了让你用动态规划来给按钮加border-radius的。

我们不会天真地以为,前端开发就是算法竞赛。如果你能把一个复杂的业务表单组件写得清晰、可维护、可扩展,在我眼里,这远比你徒手写一个红黑树要来得有价值。

所以,请你先放轻松。我们不是在考察你是不是一个“算法大神”。


那我们到底在看什么?——思路远比答案重要

既然不是看你会不会背最优解,那我们花这宝贵的20分钟,到底在考察什么?

其实,算法题只是一个“载体”,一个“媒介”。通过这个载体,我想看到的是这几样东西:

1. 你是怎么“解读”问题的(沟通与理解能力)

一个靠谱的工程师,拿到需求不会立刻动手。他会先问问题,搞清楚所有的边界和约束。

我出一道题:“写个函数,找出数组中第二大的数。”

  • 普通候选人:埋头就开始写代码。
  • 我欣赏的候选人:会先问我,“这个数组里会有重复的数字吗?会是无序的吗?会有负数吗?如果数组长度小于2怎么办?”

你看,这就是差距。我能通过这些问题,看出你是否严谨,是否有处理边界情况的意识。这个能力,在你将来面对产品经理那些模糊的需求时,至关重要。

2. 你的“思路”是否清晰(逻辑思维)

我最喜欢看到的,不是你直接写出最优解,而是你告诉我你的思考过程。

比如,你可以说:“我首先想到的,是一个最笨的办法,先排序,然后取倒数第二个。这个时间复杂度是O(n log n)。但感觉可以优化,我再想想……也许我只需要遍历一遍,用两个变量来维护最大值和第二大值,这样时间复杂度就降到O(n)了。”

这个“先暴力,再优化”的思考过程,在我看来,比你直接默写出最优解要加分得多。因为它展示了你的逻辑推理能力优化意识

3. 你的代码“品味”(工程素养)

算法题的代码量不大,但足以管中窥豹,看出一个人的代码“品味”。

你的变量是怎么命名的?a, b, c 还是 max, secondMax, current?

你有没有处理我刚才提到的那些边界情况?

你的代码有没有基本的缩进和格式?

这些细节,都反映了你平时的编码习惯。一个连算法题都写得乱七八糟的人,我很难相信他在业务项目里能写出整洁的代码。

4. 当你卡住时,你会怎么办?(抗压与学习能力)

我有时候会故意出一些有点难度的题。我不是为了让你难堪,而是想看看你卡住的时候,会有什么反应。

是直接放弃,说“不会”?还是会尝试跟我沟通,说“我卡在xxx了,能不能给点提示?”

我非常乐意给提示。我更想招一个能和我一起“协作”解决问题的人,而不是一个遇到困难就“躺平”的人。你面对一道题的态度,很可能就是你未来面对一个技术难题的态度。


给求职者的一些真心话

所以,聊了这么多:

  • 别光背题,没用。 我只要稍微改动一下题目条件,或者问你为什么这么写,背题的同学马上就露馅了。
  • 多练习“说” 。刷题的时候,试着把你的思路说出来,录下来自己听听,或者讲给朋友听。面试时的口头表达,和自己闷头做题是两回事。
  • 重点理解“为什么” 。不要满足于“这道题这么解”,要去理解它为什么要用双指针,为什么要用哈希表。理解了思路,才能举一反三。
  • 面试时,心态放平。 没做出最优解,真没关系。把你思考的过程、你的尝试、你的权衡都清晰地表达出来,你已经赢了很多人了。

我知道,让前端去卷算法,这个“游戏规则”本身就不那么公平。我们想找的是一个会思考、会沟通、有工程素养的“解决问题的人”。

算法题,只是恰好成了当前最方便、成本最低的考察工具而已。

希望这些“面试官的牢骚”,能让你稍微不那么焦虑一点。 你们怎么看?

前端登录token到底应该存在哪?LocalStorage、SessionStorage还是Cookie?一篇说透!

如果你做过任何需要登录的功能,那么你一定思考过这个问题:当后端甩给我一个token时,我一个前端,到底应该把它放在哪儿?

这个问题看似简单,无非就是 LocalStorageSessionStorageCookie 三个选项。但如果我告诉你,一个错误的选择,可能会直接导致你的网站出现严重的安全漏洞,你是不是会惊出一身冷汗?

许多开发者(包括曾经的我)不假思索地把token塞进LocalStorage,因为它的API最简单好用。但这种方便的背后,隐藏着巨大的风险。

今天,这篇文章将带你彻底终结这个纠结。我们将深入对比这三位“候选人”的优劣,剖析它们各自面临的安全威胁(XSSCSRF),并最终给出一个当前业界公认的最佳实践方案。


1. 三种存储方案对比

在做决定前,我们先来快速了解一下这三个Web存储方案的基本特性。

特性 LocalStorage SessionStorage Cookie
生命周期 永久,除非手动清除 页面会话期间(标签页关闭即失效) 可设置过期时间
存储大小 约 5MB 约 5MB 约 4KB
JS可访问性 可访问 可访问 可访问(除非设置HttpOnly
与服务端通信 不会自动发送 不会自动发送 每次HTTP请求都会自动携带

一目了然,LocalStorageSessionStorage是HTML5提供的新API,更大、更易用。而Cookie是“老前辈”,小而精,并且有个独一无二的特性:会自动“粘”在HTTP请求头里发给后端。


2. 两大安全攻击 XSS 与 CSRF

选择存储方案,本质上是在权衡安全和便利。而威胁token安全的主要是下面两种。

XSS (跨站脚本攻击)

  • 手法:攻击者通过某种方式(比如评论区)向你的网站注入了恶意的JavaScript脚本。当其他用户访问这个页面时,这段脚本就会执行。
  • 目标:如果你的token存在LocalStorageSessionStorage里,那么这段恶意脚本就可以通过简单的localStorage.getItem('token')轻松地把它偷走,然后发送到攻击者的服务器。token失窃,你的账户就被冒充了。

结论一:LocalStorageSessionStorage 对 XSS 攻击是完全不设防的。只要你的网站存在XSS漏洞,存在里面的任何数据都能被轻易窃取。

CSRF (跨站请求伪造)

  • 手法:你刚刚登录了你的银行网站bank.com,你的登录凭证(Cookie)被浏览器记住了。然后,你没有关闭银行页面,而是点开了一个恶意网站hacker.com。这个恶意网站的页面里可能有一个看不见的表单或<img>标签,它会自动向bank.com/transfer这个地址发起一个转账请求。
  • 目标:因为浏览器在发送请求到bank.com时,会自动带上bank.comCookie,所以银行服务器会认为这个请求是你本人发起的,于是转账就成功了。你神不知鬼不觉地被“伪造”了意愿。

结论二:Cookie 如果不加以保护,会受到 CSRF 攻击的威胁。


3. 现代Cookie的“优势”

看到这里你可能会想:LocalStorage防不住XSS,Cookie防不住CSRF,这可怎么办?

别急,我们的Cookie经过多年的进化,已经有了强大的防止手段。

HttpOnly - 封印JS的访问

如果在设置Cookie时,加上HttpOnly属性,那么通过JavaScript(如 document.cookie)将无法读取到这个Cookie

Set-Cookie: token=...; HttpOnly

这意味着,即使网站存在XSS漏洞,攻击者的恶意脚本也偷不走这个Cookie,从根本上阻断了XSS利用token的路径。

SameSite - 防止携带

SameSite属性用来告诉浏览器,在跨站请求时,是否应该携带这个Cookie。它有三个值:

  • Strict:最严格。只有当请求的发起方和目标网站完全一致时,才会携带Cookie,能完全防御CSRF。
  • Lax:比较宽松(现在是大多数浏览器的默认值)。允许在“顶级导航”(如<a>链接、GET表单)的跨站请求中携带Cookie,但在<img><iframe>、POST表单等“嵌入式”请求中会拦截。这已经能防御大部分CSRF攻击了。
  • None:最松。任何情况下都携带Cookie。但必须同时指定Secure属性(即Cookie只能通过HTTPS发送)。

对于登录token,我们通常希望它尽可能安全,所以SameSite=Strict是最佳选择。

Secure - 保证传输安全

这个属性很简单,只要设置了它,Cookie就只会在HTTPS的加密连接中被发送,可以防止在传输过程中被窃听。


4. 终极答案

综合以上所有分析,我们终于可以给出当前公认的最佳、最安全的方案了。

这个方案的核心是“组合拳”:将不同生命周期的token存放在不同的地方,各司其职。

我们通常有两种token

  • AccessToken:生命周期很短(如15分钟),用于访问受保护的API资源。
  • RefreshToken:生命周期很长(如7天),专门用来在AccessToken过期后,换取一个新的AccessToken

最佳存储策略如下:

  1. RefreshToken: 存放在一个 HttpOnly=true, Secure=true, SameSite=StrictCookie中。

    • 为什么? RefreshToken非常关键且长期有效,所以必须用最安全的方式存储。HttpOnly让它免受XSS攻击,SameSite=Strict让它免受CSRF攻击。前端 JS 完全接触不到它,只在需要刷新token时,由浏览器自动带着它去请求/refresh_token这个特定接口。
  2. AccessToken: 存放在 JavaScript的内存中(例如,一个全局变量、React Context或Vuex/Pinia等状态管理库里)。

    • 为什么? AccessToken需要被JS读取,并放在HTTP请求的Authorization头里(Bearer xxx)发送给后端。将它放在内存中,可以避免XSS直接从LocalStorage里扫荡。当用户关闭标签页或刷新页面时,内存中的AccessToken会丢失。
    • 丢失了怎么办? 这就是RefreshToken发挥作用的时候了。当应用启动或AccessToken失效时,我们就向后端发起一个请求(比如访问/refresh_token接口),浏览器会自动带上我们安全的RefreshToken Cookie,后端验证通过后,就会返回一个新的AccessToken,我们再把它存入内存。

这个方案完美地结合了安全性和可用性,几乎无懈可击。

一张表格说透

存储方式 优点 缺点(安全风险) 推荐用法
LocalStorage API简单,容量大,持久 XSS 不推荐存储敏感信息(如Token)
SessionStorage API简单,标签页关闭即删 XSS 同上
Cookie 可自动发送,可配置安全属性 CSRF (若无SameSite) 不推荐直接存AccessToken
内存 + HttpOnly Cookie 安全 (防XSS+CSRF), 体验好 方案略复杂 最佳实践 (AccessToken存内存,RefreshTokenHttpOnly Cookie)

希望这篇文章能彻底帮你理清思路。当你在实践中或者面试被问到时,就可以把这套“方案”发挥出来。

谢谢大家🙂

📌 你可以继续看我的系列文章

❌