coverPiccoverPic

记录一个 VueUse 的小坑

背景

最近遇到一个bug,跳转到某些页面后,浏览器地址栏url上面的query参数神秘消失,引起一些接口传参异常影响页面内容获取。Url从testUrl/user?userId=xxx变成了testUrl/user

Bug出现前后涉及一个网络请求的代码,就像这样子:

ts
  1. <script setup lang="ts">
  2. import axios from 'axios'
  3. import { getUrlParams } from './utils';
  4. const testHandler = () => {
  5. const params = getUrlParams()
  6. delete params.userId
  7. axios.post('testUrl', { ...params })
  8. }
  9. </script>

排查

先后经过了console.log大法和浏览器断点调试,仍然无法确定bug的原因,由于bug和url有关,猜测是不是因为有没有注意到的代码修改了url,于是在本地重写了hitsory的方法:

ts
  1. const oldReplace = history.replaceState
  2. history.replaceState = function (..._arg) {
  3. console.trace()
  4. oldReplace.apply(this, _arg)
  5. }
  6. const oldPush = history.pushState
  7. history.pushState = function (..._arg) {
  8. console.trace()
  9. oldPush.apply(this, _arg)
  10. }

捕捉到调用栈:

  1. console.trace
  2. history.replacestate
  3. write
  4. ......
  5. useUrlSearchParams
  6. getUrlParams
  7. ......

可见是getUrlParams引起的:

ts
  1. import { useUrlSearchParams } from "@vueuse/core"
  2. export const getUrlParams = (key: string) => {
  3. const params = useUrlSearchParams('history')
  4. return key ? params[key] : params
  5. }

也就是说,是VueUse的useUrlSearchParams方法重写了url,翻了一下它的文档(useUrlSearchParams | VueUse)和源码,发现useUrlSearchParams返回的是一个响应式对象,对象被修改了会同步到url上面:

js
  1. function write(params, shouldUpdate) {
  2. pause();
  3. if (shouldUpdate)
  4. updateState(params);
  5. window.history.replaceState(
  6. window.history.state,
  7. window.document.title,
  8. window.location.pathname + constructQuery(params)
  9. );
  10. resume();
  11. }
  12. function onChanged() {
  13. if (!enableWrite)
  14. return;
  15. write(read(), true);
  16. }

修改参数对象触发onChanged,然后被write方法写到url上面。

解决

问题原因找到了,我们注意到enableWrite这个变量可以阻止重写url。看到:

js
  1. function useUrlSearchParams(mode = "history", options = {}) {
  2. const {
  3. initialValue = {},
  4. removeNullishValues = true,
  5. removeFalsyValues = false,
  6. write: enableWrite = true,
  7. window = defaultWindow
  8. } = options;
  9. // ...
  10. }

这个getUrlParams工具方法是拿来获取url参数的,并没有用来修改过url,为了以后避免这种bug,把上面的write参数加上bug就修复了。

ts
  1. useUrlSearchParams('history', { write: false })

小吐槽:看文档的时候write这个配置项好像不太显眼,只在Changelog上面有小小的一行

0 条评论未登录用户
Ctrl or + Enter 评论
© 2023-2025 LittleRangiferTarandus, All rights reserved.
🌸 Run