一个组件,一个hook,让你在本地开发环境中拿到微信code

前言

众所周知,初次接触微信相关生态铁定是头疼的,用微信API第一步就得拿到微信code, 官方上说这么操作,实际业务上体现就是:需要code的页面首先得重定向到微信的授权地址上面去,并且要携带上你当前项目的域名(redirect_uri)和AppId还有其他同样重要的参数(response_type、scope、#wechat_redirect、state等),授权成功后会重新重定向回你的域名上并为你的域名拼接上code。 至此一个code就到手了,能完成上面流程的代码和具体参数的意思一搜一大把,我这就不再赘述唠。今天要说的是本地开发环境中如何优雅(奇技淫巧)的获取微信code😆

痛点:痛!太痛了!

不用我说,大伙都知道,微信网页授权的过程中携带的redirect_uri,也就是你项目的域名必须在微信公众平台里配置为网页授权域名

实际开发中,我们至少得配置生产域名和测试域名。但真正糟心还是属本地环境下如何调试,如何去获得code, 我所知道市面上常用的法子是配置测试域名, 还有就是内网穿透。这两种方式配置都很麻烦,对于小白不是很有好。尤其后者对于没有网络基础的小白听着就有些劝退。

踩坑后的顿悟

自己刚开始接触到h5项目时,为了得到这个code,每次测试都自己部署到线上去测,只因为线上域名在公众号中配置过,也只有通过线上域名能拿到code。而且这样反复部署过于繁琐又非常不安全,太容易翻车。虽然通过配配置测试域名成功在本地拿到过code, 但后端同样需要配置,鉴定为麻烦,放弃!内网穿透,鉴定为搞不懂,放弃!😂

所以后面擅长放弃的我想了个办法,反正目的只是拿code, 用点下流(愚蠢)的手段又不是不可以:
首先我先在微信开发者工具中打开项目的线上地址,调慢网速,手动去把得到code扣下来,然后我再往我本地地址上面一复制,铛铛!完成!本地环境成功拿到了线上code!🤗

但实际这么操作几次,发现依旧蛋疼,code用一次就废了,新的code还要用上面的方式去获取一次。

所以有没有那么一种方式,不用我再手动去拿code, 再复制?也不去配置那些多余域名?也不用做那我还搞不懂的内网穿透?最好就用框架本身去解决?用js代码去解决?答案是可以的!🤩

以下是下流手段转化为优雅代码的过程

  1. 首先需要前往微信公众平台配置一个,合法的网页授权域名。(官网如是说)
  2. 开发一个名为传送门的组件,并将该组件挂载到前端路由上,如/portal,然后项目部署至刚才配置过的合法域名上;
  3. 接着封装一个useWxCode的hook, 它可以与传送门 相联动
  4. useWxCode在任何一个需要code的页面直接调用即可,生产环境下可以正常往微信授权网址跳转,并获取code,然后重定向回来。但在开发环境中,当向微信授权网址重定时,useWxCode将会带着当前本地Url作为参数往线上的传送门组件的路由上跳转。当跳到线上的传送门时code其实已经到手了,而传送门的唯一一项工作就是,将路径参数里的本地Url与code以及其他参数拼接起来作为重定向的路径并进行跳转。至此大功告成!😎

can can need code

我是在react中实现的,但主要都是以TS为主,其他任何框架稍微改改也能使用,废话少说,上代码:

传送门组件 (PortalComponent)

创建 portalComponent.tsx ,且为其注册路由。对应上面第二个步骤,

该组件的作用是:路径中存在code时,将路径参数里的本地Url与code以及其他参数拼接起来作为重定向的路径并进行跳转。

PortalPath 为传送门组件的 路由名 + ?,传送门组件与hook都会用到该参数参与路径拼接,所以建议写在公共配置文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// portalComponent.tsx
const PortalPath = 'portal?';
export default function PortalComponent() {
const code = React.useRef<string>(geUrlParam(location.href)?.['code']);
React.useEffect(() => {
if (code.current) {
const hash = '#/';
/* 微信授权地址上的redirect_uri进行了encodeURIComponent处理,
所以这里必须使用decodeURIComponent进行解析。 */
const originalUrl = decodeURIComponent(location.href.split(PortalPath)[1]);
const redirectUrl = originalUrl.split(hash)[0] + `?code=${code.current}` + hash + originalUrl.split(hash)[1];
window.location.href = redirectUrl;
}
}, []);
// 返回空标签都行,但这里我用了个过渡的loading组件
return <LoadingComponent />;
}
1
2
3
4
5
6
7
// route.ts
{
path: '/portal',
component: () => import('./portal-component/portal.component'),
lazyload: true,
exact: true
}

获取Url中参数的方法

1
2
3
4
5
function geUrlParam(search: string) {
const param: Record<string, any> = {};
search.replace(/([^&=?]+)=([^&]+)/g, (m, $1, $2) => (param[$1] = $2));
return param;
}

useWxCode (hook)

创建 useWxCode.ts 。对应上面第三个步骤

此hook,封装了自动获取微信code的逻辑代码,也暴露了code, wxLoading等状态, 以及刷新code的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
export const PortalPath = 'portal?';

export const WxState = { wxLoading: true };

export interface WxCodeHookOpt {
/** 拿到code后将重定向的前端路由,例如:login | login?a=123&b=456 */
route: string;
/** 拿到 code 后立即执行的方法 */
getCodeAfterFn?: (code: string) => void;
/** 是否页面初始化就跳转微信鉴权页面获取Code,默认:true */
isPreGetCode?: boolean;
/** WX授权方式 默认:snsapi_userinfo */
scope?: 'snsapi_userinfo' | 'snsapi_base';
}

export interface WxCodeHookRes {
/** 微信code */
code: string;
/** 刷新|获取 微信code */
refreshCode: () => void;
/** 获取wxCode时的loading状态 */
wxLoading: boolean;
}

/** 在需要微信code的h5页面中使用 */
export function useWxCode(wxCodeHookOpt: WxCodeHookOpt): WxCodeHookRes {
const [state, setState] = useState(WxState);
const { wxLoading } = state;
const { route, getCodeAfterFn, isPreGetCode = true, scope = 'snsapi_userinfo' } = wxCodeHookOpt;
const code = useRef<string>();
// 判断路径中是否已存在code,存在code,关闭wxLoading, 执行 getCodeAfterFn;
// 不存在code, 通过isPreGetCode判断 是否需要自动获取code。
useEffect(() => {
code.current = geUrlParam(location.href.split('#/')[0])['code'];
if (code.current) {
setState({ wxLoading: false });
getCodeAfterFn && getCodeAfterFn(code.current);
} else {
isPreGetCode ? refreshCode() : setState({ wxLoading: false });
}
}, []);

// 刷新|获取 微信code
function refreshCode() {
// 开发环境会重定向到线上的[传送门]组件中获取code,获取code后再带着code返回源地址
// 正式环境则直接跳微信授权网址获取code
const noCodeUrl = location.href.split('?code=')[0] + location.hash;
const devHref = code.current ? noCodeUrl : location.href;
const devGetCodePath = PortalPath + devHref;
const routePath = process.env.NODE_ENV === 'development' ? devGetCodePath : route;
// process.env.REDIRECT_URL 就你的线上地址,也就你所配置的公众号合法的网页授权域名。
const str = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${
process.env.appId
}&redirect_uri=${encodeURIComponent(
process.env.REDIRECT_URL + routePath
)}&response_type=code&scope=${scope}&state=123#wechat_redirect`;
window.location.href = str;
}

return {
refreshCode,
code: code.current,
wxLoading
};

使用

在任何需要使用微信code的页面,直接调用 useWxCode 即可!暴露的 code, wxLoading, refreshCode ,可以满足你后续代码有关code的任何需求!

1
2
3
// xxx.tsx
const { code, wxLoading, refreshCode } = useWxCode({ route: 'home' });
// do anything ...

使用useWxCode后,开发环境会重定向到线上的[传送门]组件中获取code,获取code后再带着code返回源地址; 正式环境则直接跳微信授权网址获取code

效果

从此开发h5页面,只需配置一个公众号授权域名,无论测试环境,还是本地开发环境,只需添加如上代码,获取code,就是这么丝滑~

f.gif

最后的最后

这里是萌新小把子,这是我第一篇技术文章,期待各位大佬狠狠的指点~!😆


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!