和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 的使用: typescript 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)

}) })

实现

typescript 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,就可以实现从微信小程序和网站共享登录状态,有一种跨越设备的单点登录效果。