由于 server components 的渲染早于 client components ,而且无法访问 context ,所以需要在两者之间共享 state 尤其是将客户端的变更反映到服务器端组件的时候,我现在想到的方法就是修改 url query params 然后跳转到这个新 url 。 网上也有一些提倡这样做的文章和视频,比如: https://youtu.be/ukpgxEemXsk?si=Dd9vJVfA4HBU0do3 https://dev.to/jeffsalive/solving-the-challenge-of-state-persistence-in-nextjs-effortless-state-management-with-query-parameters-4a6p
感觉大体上这种做法是可行的,但我如果客户端的状态比较复杂的话会不会带来问题?
1
BugCry 2023-10-28 11:23:13 +08:00 via Android
1 ,URL 的长度有限制
2 ,如果 state 被恶意修改,阁下将如何应对? |
2
hugepizza 2023-10-28 11:53:33 +08:00
cache revalidate 也是个问题 官方文档上的 revalidatePath 没有写是否支持 searchParams
至于 revalidateTag 我到现在也没搞懂这是个啥 🤣 |
3
rocmax OP @BugCry 1 确实是一个硬性的限制,浏览器限制在 2048 字符以下,一般而言是够的,如果把使用 url 存储 state 作为一个原则的话可能会遇到极端情况无法处理。长 url 还会带来难以记录和共享的问题,优势是能将 app 恢复到特定状态。
第 2 点风险在哪里?客户端 state 本来就存在客户端,不管存在 context ,localstorage 还是 cookie 里,客户都是随便改的,服务端反正都得做验证,需要应对什么? |
4
gap 2023-10-28 15:50:06 +08:00 via iPhone
我之前看到一个 hack 方案,将状态 hash 后再放到 url param 上去
|
5
a632079 2023-10-28 18:23:56 +08:00
Server Components 里我记得可以 Read Cookies ,因此,分页,filter 外的参数,还是使用 Cookies 共享更方便。
Ref: https://nextjs.org/docs/app/api-reference/functions/cookies P.S NextJS 官方是建议 Server Actions Mutation 时才能修改 Cookies ,RSC 由于 Response 流已经发送,无法设置 Cookies ,但是社区有人做了 Cookies 的方案,实现了 Cookies 共享。 |
6
a632079 2023-10-28 18:44:18 +08:00
@hugepizza 看起来应该是支持 revalidate searchParams 的。revalidateTag 就是和 Redis Cache Key ,TanStack Query 的 queryKeys 一样的东西,fetch 是可选设置,第三方数据库比如说 DB 拉来的,就得手动设置 tag 了。
Ref: https://nextjs.org/docs/app/api-reference/functions/unstable_cache (应对第三方数据源的缓存函数) Ref: https://nextjs.org/docs/app/building-your-application/caching#apis (不同 API 对缓存的影响) Ref: https://nextjs.org/docs/app/building-your-application/caching#data-cache (Fetch 相关的缓存工作在数据缓存中) |
7
BugCry 2023-10-28 19:31:10 +08:00 via Android
@rocmax 既然说到 cookie ,如果加了 http-only 属性,就算是用 js 都读取不出来,然而放 URL 则是完全暴露
|
10
rocmax OP @BugCry 从 url 拿到的都是值,react 也会对内容转义,基本不可能会被当成逻辑执行。我的理解将 state 放在 url 里至少不会更不安全。
有什么 xss 的实际例子吗? |
11
Pencillll 2023-10-29 06:59:52 +08:00
1. 所有状态都放 url 里代表着任何人都可以通过 CSRF 的形式来控制页面的初始状态,也就是页面上的所有状态都是不可信的 user input ,所以不仅后端要验证所有数据,连前端也得验证所有数据(状态),否则会和遭受和后端一样的攻击
2. 用户分享链接时大概率会直接复制整个 url 给别人,如果其中包含 token 之类,别人点进来就会直接登入他的账号 3. 浏览器的前进/后退功能会挂掉,比如进入一个新页面,随后修改了主题颜色,这时返回到前一个页面会使修改失效 |
12
rocmax OP @Pencillll 1. 后台本来验证就不能省,页面反正在客户端,用户怎么折腾又没法管,其他的 state 保存方式并不能避免这些问题。
2. 用户认证是另外的问题,用 url 管理 state 并不会将 token 也存在 url 里。共享带 state 的 url 可以让对方直接到达特定的 app 状态,这其实是优势。 3. 主题颜色不涉及到 client 和 server component 之间的状态传递,放在顶层的 theme provider 里即可。同第二点,这种做法可以让前进/后退在历史状态序列里移动而不是只跳转页面,很多情况下是更方便的。如果针对琐碎的输入不想将每个状态都存入历史,可以在跳转的时候使用 replace 而不是 push 。 |
13
yanggggjie 2023-10-31 15:35:05 +08:00
[next-usequerystate - npm]( https://www.npmjs.com/package/next-usequerystate)
op 看看这个库呢 |