在微信小程序中使用 Cookie

哈德韦

共 7992字,需浏览 16分钟

 · 2023-10-14

和Web相比,微信小程序有哪些限制?

微信小程序作为一种独立的应用开发平台,与传统的 Web 应用相比,存在一些特定的限制和差异。了解这些限制对于在微信小程序中集成身份认证平台至关重要。在本节中,我们将介绍微信小程序相对于 Web 应用的主要限制。


以下是一些微信小程序的限制:


  • 运行环境限制:微信小程序运行在微信客户端中,无法直接在浏览器中访问。因此,一些基于浏览器的功能(如 Cookie 等)在微信小程序中不可用。

  • 网络请求限制:微信小程序中的网络请求受到严格的安全策略限制。只能发送 HTTPS 请求,且只能访问特定的域名。这意味着在集成身份认证平台时,需要确保认证服务提供商的域名在微信小程序的白名单之中。

  • 文件系统限制:微信小程序具有受限的文件系统访问权限。只能访问小程序自身的文件系统,无法直接读取用户本地文件或系统文件。

  • UI 组件限制:微信小程序提供了一组特定的 UI 组件,相对于 Web 应用的 UI 组件更加有限。需要根据微信小程序的组件库进行布局和样式设计。

  • 代码运行限制:微信小程序使用的是基于 JavaScript 的开发语言,但与 Web 应用相比,微信小程序的 JavaScript 运行环境具有一些差异。需要熟悉微信小程序的开发规范和限制,以确保身份认证功能的正确实现。

通过自定义 Cookie 存储对接网络请求的 set-cookie

尽管在微信小程序中没有像浏览器那样的原生 Cookie 存储,但如果有需要,比如在和身份认证平台交互过程中,非常需要客户端有 Cookie 存取功能的话,可以使用自定义的 Cookie 存储来实现。

好在,不用完全从0开始造轮子,我们可以基于 tough-cookie封闭几个常用的接口,以便在微信小程序中灵活地读取和存储网络请求中的 Cookie,不妨将自己封装的文件命名为 browser-cookie.ts。

规格说明

我们用一个测试文件说明对 browser-cookie 的使用:

import {Cookie} from "tough-cookie";import * as assert from "assert";import {BrowserCookieStore} from "./browser-cookie";
describe('Browser Cookie Store', () => { const sut = new BrowserCookieStore()
it('finds cookie', (done) => { sut.findCookie("test", "test", "key", (_err: Error | null, cookie: Cookie | null) => { expect(cookie).toEqual(null);
done() }); })
it('finds cookies', (done) => { sut.findCookies("test", "test", false, (_err: Error | null, cookies: Cookie[] | null) => { expect(cookies).toBeDefined() expect(cookies!.length).toEqual(0)
done() }); })
it('gets all cookies', (done) => { sut.getAllCookies((_err: Error | null, cookies: Cookie[]) => { expect(cookies.length).toEqual(0)
done() }) })
it('puts cookie', (done) => { sut.putCookie(Cookie.parse("foo=bar")!, (err: Error | null) => { expect(err).toEqual(null)
sut.getAllCookies((_err, cookies) => { expect(cookies.length).toEqual(1)
sut.putCookie(Cookie.parse("joe=doe")!, (err2) => { expect(err2).toEqual(null)
sut.getAllCookies((_, allCookies) => { expect(allCookies.length).toEqual(2) }) })
done() }) })
})
it('removes cookie', (done) => { sut.getAllCookies((_err, cookies) => { expect(cookies.length).toEqual(2)
sut.removeCookie('', '', 'foo', (err2) => { expect(err2).toEqual(null)
sut.getAllCookies((_, allCookies) => { expect(allCookies.length).toEqual(1)
done() }) }) }) })
it('removes all cookies', (done) => { sut.getAllCookies((_err, cookies) => { expect(cookies.length).toEqual(1)
sut.removeCookies('', '', () => { sut.getAllCookies((_, allCookies) => { expect(allCookies.length).toEqual(0);
done(); }) }) }) })
it('update cookie', (done) => { const cookie = Cookie.parse(`foo=bar`) assert.ok(cookie)
sut.putCookie(cookie, () => { sut.getAllCookies((_, allCookies) => { expect(allCookies.length).toEqual(1) expect(document.cookie).toEqual(`foo=bar`)
const newCookie = Cookie.parse(`foo=doe`) assert.ok(newCookie)
sut.updateCookie(cookie, newCookie, () => { expect(document.cookie).toEqual(`foo=doe`) done() }) }) }) })
it('finds cookie without allowSpecialUseDomain', (done) => { const cb = (err, cookies) => { expect(err).toEqual(null) expect(cookies.length).toEqual(0)
done() }
sut.findCookies('www.zhihu.com', '/api/v3/oauth/captcha', cb) })})

实现

import {Cookie, CookieJar, Store} from "tough-cookie";
type FindCookiesCallback = (err: (Error | null), cookie: Cookie[]) => void
export class BrowserCookieStore implements Store { synchronous: boolean;
findCookie(domain: string, path: string, key: string, cb: (err: (Error | null), cookie: (Cookie | null)) => void): void { const decodedCookie = decodeURIComponent(document.cookie)
decodedCookie.split(';').forEach(c => { while (c.startsWith(' ')) { c = c.substring(1) }
const name = key + '=' if (c.startsWith(name)) { cb(null, Cookie.parse(c.substring(name.length, c.length)) ?? null) } });
cb(null, null) }
findCookies(domain: string, path: string, cb: FindCookiesCallback): void findCookies(domain: string, path: string, allowSpecialUseDomain: boolean, cb: FindCookiesCallback): void findCookies(domain: string, path: string, allowSpecialUseDomain: boolean | FindCookiesCallback, cb?: FindCookiesCallback): void { if (!cb) { cb = allowSpecialUseDomain as FindCookiesCallback }
const decodedCookie = decodeURIComponent(document.cookie) const cookies: Cookie[] = []
decodedCookie.split(';').forEach(c => { const cookie = Cookie.parse(c)
if (cookie) { if (domain && path) { if (cookie.domain === domain && cookie.path === path) { cookies.push(cookie) } } else { cookies.push(cookie) } } })
cb(null, cookies) }
getAllCookies(cb: (err: (Error | null), cookie: Cookie[]) => void): void { this.findCookies('', '', false, cb) }
putCookie(cookie: Cookie, cb: (err: (Error | null)) => void): void { console.log('put cookie = ', cookie); document.cookie = cookie.toString()
cb(null) }
removeCookie(domain: string, path: string, key: string, cb: (err: (Error | null)) => void): void { this.getAllCookies((_, allCookies) => { allCookies.forEach(c => { if (c.key === key) { document.cookie = `${c.key}=${c.value};max-age=0;` } })
cb(null) }); }
removeCookies(domain: string, path: string, cb: (err: (Error | null)) => void): void { this.getAllCookies((_, allCookies) => { allCookies.forEach(c => { document.cookie = `${c.key}=${c.value};max-age=0` })
cb(null) }) }
updateCookie(oldCookie: Cookie, newCookie: Cookie, cb: (err: (Error | null)) => void): void { this.removeCookie('', '', oldCookie.key, () => { this.putCookie(newCookie, () => { cb(null) }) }) }
}
const cookieStore = new BrowserCookieStore()cookieStore.synchronous = true;
export const getCookieStore = () => { return cookieStore}
export const clearCookieStore = () => { cookieStore.removeCookies('', '', () => { }) return cookieStore}
export const getCookieJar = () => { return new CookieJar(cookieStore)}

实际用途

很多网站的登录状态都依赖 Cookie,通过在微信小程序里利用网站 cookie,就可以实现从微信小程序和网站共享登录状态,有一种跨越设备的单点登录效果。

浏览 37
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报