作者: meathill

  • 使用 Vercel、Supabase、Stripe 打造 OpenAI 计费系统:2. 处理用户注册/登录

    使用 Vercel、Supabase、Stripe 打造 OpenAI 计费系统:2. 处理用户注册/登录

    嗯,是的,我回来填坑了。既然要打广告,就要对得起各位金主,总是水文是不行的,还是要输出干货。

    广告继续。本博客即日起开始常年招商,欢迎各位想推广产品的老板投广告,目前定价 4800/年,亦可增加评测文章、教学文章配合,详情可与我联系。具体详情更新在 本站广告 2023 年招商


    Supabase 用户体系入门

    Supabase 提供 Serverless 数据库,自带用户体系,开发用户系统非常简单。而且 SDK 很完善,适配各种框架,大部分功能开箱即用;官方教程方面做得也很好。所以,首先请大家先认真阅读这两篇官方文档、教程:

    第二篇教程文章详细的介绍了使用 Supabae 开发用户管理系统的过程,配合上面的文档,相信大家都可以轻松入门。唯一的难点(对部分同学来说)可能是英文,我就先不复述。

    接下来的文章主要介绍官方没有细说的最佳实践和各种实用细节。

    邮件登录与邮件模版

    虽然官方提供了很多方案,但是我想,对于大部分同学来说,邮件+密码登录才是最常用的,最多再加上第三方比如 Gmail 登录。

    Supabase 提供了发邮件的功能,方便用户校验邮箱、找回密码。但是,正如很多邮件服务器那样,它的到达率并不理想。我猜测有些用户即使没有滥用 Supabase 的邮件服务,也会因为邮件模版过于简单而被误杀。所以大家第一步应该先配置邮件模版,尽量多体现自己的产品相关信息,尽量跟大家的通用模版区分开,减少误报误杀的可能。

    Supabase 默认要求用户校验邮箱之后才能登录,如果你暂时不关心这一点,可以考虑在 Auth ProviderS > Email关掉这个功能。此后,用户完成注册后就可以登录,不过他们的用户状态在数据里仍然是未验证,我们也可以借此对用户进行一些差异化的控制。

    注册与登录,自动注册

    有一点我不太喜欢。Supabase 提供两个方法:signUpsignInWithPassword,分别用来注册和登录。但是通常情况下,我并不希望区分这两个方法。我认为我们的网站对用户来说,只是一个小工具,我觉得他们不会在意是否在这里注册过,他们只希望做他们要做的事情,注册登录只是我们为了方便自己而做的步骤。

    所以我一般仍然会通过不同的路径区分用户是想注册,还是想登录。但是我会在用户 signUp 后检查错误信息,如果是重复注册,就自动帮他们登录。

    const { data: { user }, error } = await supabase.auth[method]({
      email,
      password,
      options,
    });
    if (error) {
      // registered, login
      if (error.message === 'User already registered') {
        return login(email, password);
      }
    throw error;
    }

    Nuxt3+Pinia 实现用户身份校验及额度查询

    教程中的例子比较简单,通常来说我们的产品会复杂很多,比如,我们可能需要全局状态管理工具,方便不同页面不同组件中使用。在 Nuxt3 中使用 Pinia 需要用到特有的 Module:@pinia/nuxt,简单安装官方教程配置一下即可。这里主要分享我摸索的其它未提及要点。

    额度查询

    Supabase 在创建项目的时候已经帮我们建好了用户表,并且放在默认不对外的库里面。所以我们最好不要直接修改表,而是如教程所讲,创建一个新的表,把用户账户相关的其它数据放进去,比如在这样一款典型的 ChatGPT 产品中,就是帐户额度,然后通过关联 id 的方式访问。

    这就带来一个问题:什么时候去读这个表?

    对 SPA 来说,这个问题比较简单,登录之后,以及网页初始化的时候读取即可,反正所有请求都由我们全权控制。但是对于 Nuxt3 来说就值得讨论一下。因为 Nuxt3 要进行服务器端渲染,所以我们通常希望它在渲染页面的时候,这个数据已经就位了。

    这里我推荐配合 Pinia Store,使用 supabase.auth.onAuthStateChange 函数。我会建立一个 userStore,在里面完成用户注册、登录、登出等动作,同时注册 onAuthStateChange 事件,完成用户状态变更后的处理。

    const useUserStore = defineStore('user', () => {
      const supabase = useSupabaseClient();
      const user = useSupabaseUser();
    
      async function login(email: string, password: string, isSignUp = false): Promise<void> {}
      async function loginWithGoogle(): Promise<void> {}
      async function logout(): Promise<void> {}
      
      // 注册事件处理函数
      supabase.auth.onAuthStateChange((event, session) => {
        switch (event) {
          case 'INITIAL_SESSION':
          case 'SIGNED_IN':
          // 在这里处理登录后和初始化时拿到用户身份后的操作,比如加载用户账户的额度
          // 这里需要注意:此时 `user.value` 尚未被填充,所以我们不能依赖它。有两个方案:1. 延迟执行 `setTimeout`;2. 直接从 `session` 参数里拿到用户信息然后处理
          // 我的做法是,如果需要请求 API,那就选择方案2;否则,使用方案1,等 100ms
        }
      });
    });
    export useUserStore;

    请仔细看上方代码的注释,非常重要,看起来很简单,但其实是血泪铺就的道路。

    判断第三方登录,及 UI 呈现

    当用户选择第三方登录,比如 Gmail 的时候,Supabase 目前只支持跳转这一种方式,不如 Auth0,可以用 popup,省很多事。

    完整的第三方登录流程是:

    1. 跳转到第三方登录页面
    2. 登录
    3. 跳转到 Supabase 中间页
    4. 带着 access_token 跳回我们的网站,Supabase SDK 负责读取 access_token,验证用户身份等工作

    其中涉及到两个(或更多)网站的配置,因为文档中写的有,我就不再详述,需要的同学留言我再补充。

    最麻烦的是(4),跳转回来之后,从页面初始化成功到完成登录,中间可能会隔很久,短则1、2秒,长则10s 都有可能。这期间用户可以继续操作,会产生各种误会和误操作。这里我建议:

    1. 登录时传递 redirectTo,要求最终跳转页面是某个登录落地页
    2. 初始化的时候,检查 URL 里的 #access_token=
    3. 如果有,说明是第三方登录返回,然后就显示登录中的状态
    4. 等待 user.value 变化,说明完成登录,跳转到原先应该去的页面,或者继续之前没做完的操作
    5. 如果没有 access_token,直接跳转到其他落地页。

    总结

    上面这些内容看起来不复杂,但实际上对用户体验影响很大,并且文档、教程说得也不清楚,导致我的老板对产品一直不太满意。希望这篇文章可以节省大家的宝贵时间。

    如果有关于 Supabase、Vercel、Nuxt3 的问题,欢迎评论里面留言。

    系列文章

    1. 使用 Vercel、Supabase、Stripe 打造 OpenAI 计费系统:1. 系统篇
    2. 【本文】使用 Vercel、Supabase、Stripe 打造 OpenAI 计费系统:2. 处理用户注册/登录

    建议阅读

  • 本站广告 2025 年招商

    本站广告 2025 年招商

    去年招商比较成功,得到三家赞助商的垂青,感谢大家的支持。今年继续。

    蛇年伊始,开启本博客的 2025 年度广告招商。各位金主大哥大姐赶紧来投呀!

    广告周期:一年;赞助费用:4800/年。含一个对联广告+一个文章底部广告(可开发票)。 亦可定制评测文章、教学文章、教学视频等,按照年度框架的方式来进行。

    我的博客目前访问量基本上工作日 200~300 uv,周末 100,发文期间更高。访问者大部分是 AIGC、前端、全栈开发者、独立开发着,本着学习和交流的目的前来。部分关键词,比如前端、ChatGPT、全栈、Supabase、Shopify 等访问量不错。

    有意者请私信联系,欢迎转发介绍。

  • 【转发招聘】OpenResty 招聘内容编辑

    【转发招聘】OpenResty 招聘内容编辑

    OpenResty Inc 目前有一个推广内容编辑的职位,月薪 5000 ~ 9000 元人民币,取决于工作经验。希望能尽快找到细心和有责任心的员工。全职和兼职都接受。兼职需要保证每周至少 25 小时的工作时间。岗位要求如下:

    1. 熟练使用常见的视频编辑软件,
    2. 熟练使用 macOS 或 Linux 操作系统,包括终端命令行和图形界面,
    3. 需要有一定的英语读写能力,有听说能力加分。
    4. 需要有较强的中文读写能力。
    5. 有一定的计算机技术背景的同学优先,但不要求编程能力。
    6. 能使用 markdown 文档标记语言加分,
    7. 会使用 git 软件,熟悉版本控制。
    8. 学习能力强,对新事物有好奇心。
    9. 应届毕业生也接受。有企业实习经验或开源贡献经验会加分。
    10. 有在技术类或互联网公司任职经验的同学优先。

    可以自己选择工作城市(不一定是中国大陆),或者到我们的深圳办公室。中国大陆的全职岗位,我们会通过中国子公司签订正式的劳动合同,并在当地城市缴纳五险一金。同时会授予一定数目的我们美国公司的股票期权。

    我们没有 996,外企文化。

    有兴趣的同学可以将自己的简历尽快发送到 talents@openresty.com 这个邮箱。

    先到先得。非常感谢!

  • 【转发招聘】【广州】夸克 App 前端

    【转发招聘】【广州】夸克 App 前端

    近期太忙,博客更新很少,于是流量就下降。正巧看到朋友的招聘信息,转发一下促进首页更新。


    1. 负责夸克App前端业务的开发和维护,包括但不限于搜索结果页、夸克文档等前端内容业务;
    2. 负责前端业务的架构设计工作,推进整体方案拉通及实现落地,并通过技术的手段持续改善性能和体验;
    3. 主导或参与创新产品技术方向探索和业务落地,参与到Flutter、Serverless等新技术的建设和推广落地当中。
      职位描述
    4. 2年以上工作经验,精通各种前端技术(包括HTML/CSS/JavaScript等),熟悉ES6语法,熟悉网络协议(HTTP/SSL),熟悉常见安全问题和对策;
    5. 精通主流的前端框架,如react/vue/angular等,精通前端构建工具,如 Webpack / FIS等;
    6. 熟悉nodejs 相关知识,并有express/koa等的实践经验,或有其他后端开发经验;
    7. 擅长性能优化,有架构设计能力,有过大规模复杂项目开发背景;
    8. 对前端技术有持续的热情,良好的团队协作能力,提升团队研发效率,实现极致性能,通过创新交互优化产品体验;
    9. 具备客户端能力或者Native&Web技术融合经验优先;
    10. 具备大规模/高负载场景下NodeJS应用开发、运维经验优先。

    据说上限到 P7,有股票。

    感兴趣的话联系我吧,我帮忙转简历。

  • Nuxt 3 最佳实践与常见问题

    Nuxt 3 最佳实践与常见问题

    最近比较忙,也有些犯懒,所以博客视频都没怎么更新。今天一看,竟然断更将尽一个月,那无论如何得攒点东西。就把前阶段的笔记贴出来吧,是我使用 Nuxt3 的一些经验心得,希望对大家有所帮助。

    如果大家在使用 Nuxt3 期间有经验可以分享,或者问题需要讨论,欢迎留言。

    Nuxt 3 简介

    Nuxt.js 是一个基于 Vue.js 的服务端渲染应用框架,可以帮助开发者快速构建出高性能、SEO 友好的 Web 应用。Nuxt.js 3 是该框架的最新版本,它具有更快的启动时间、更快的构建时间和更先进的开箱即用功能。

    然而,在使用 Nuxt.js 3 进行项目开发时,我遇到了不少问题。本文会记录这些问题,以及我的经验。

    最佳实践

    下面是我从之前的问题里找到的最佳实践,应该问题不大,可以照搬。

    部署

    Nuxt 3 可以直接部署在 Vercel,兼具 SEO 与高用户体验。

    Serverless function

    默认情况下 Nuxt3 /api 和渲染都走 serverless function,理论上要弱于 Edge Function。我曾试着切换到 Edge Function,服务立刻就挂了,回头找个小服务摸索一下试试看。

    目前来看效能还可以,暂时没有体感延迟。我建议大家不要强求,把切换功能留给 Nuxt 核心团队来处理吧。

    加载远程数据

    SSR

    使用 useFetchuseAsyncData,Nuxt 会先加载远程数据,然后渲染页面,再进行页面的跳转。

    注意:SSR 阶段,组件发出的请求不会携带 cookie,这个设计是有意为之,避免个性化数据错误的出现在缓存层里面。如果希望 SSR 中包含个性化数据,可以手动操作,但请务必小心,不要泄漏不必要的请求头,因为可能带来安全隐患。

    具体做法可以参考官方文档:Passing Headers and cookies

    先跳转,再加载

    使用 useLazyFetchuseLazyAsyncData,Nuxt 不会等待请求完成,它会先渲染页面并跳转,然后在数据加载完成之后,更新视图。

    平时加载数据

    如果我们要像平时使用 Vue 那样加载数据并渲染,最好使用 $fetch

    使用 pendingrefresh 等复用请求代码

    比如页面里我们远程加载了一个对象,然后接下来,我们要重新加载这个对象,或者我们要根据某个参数加载别的对象,就可以利用 useFetchuseAsyncData 等返回的 pending 来渲染状态,或者用 refresh 重新发起请求,复用请求代码。

    尽量使用 default() 返回默认值

    很多时候我们远程加载的数据不是简单对象(文本、数字等),而是某个比较复杂的对象,比如一篇文章、一组人员数据。通常来说组件里的模版就负责渲染这组数据,如果不返回默认值,渲染可能会出错,可能导致页面跳转失败。

    所以我建议大家尽量返回默认值。

    配置 routes

    Nuxt 默认会对每个页面进行服务器端渲染,但很多时候我们并不需要,比如各种后台页面。所以我建议项目起始阶段就把各页面的渲染策略制定好。

    参考文档:Rendering Modes · Nuxt Concepts对首页、关于我们之类的纯静态页面,可以启用预渲染(preredering);对后台页面,就禁用 ssr;等。

    但是,大家也要小心错误的缓存机制,可能会把不应该缓存的页面缓存下来,造成渲染出错。

    使用 localStorage

    我们知道,Nuxt3 最大的特性就是 SSR,它会在服务器端渲染完页面,再返回给客户端。而 localStorage 顾名思义,只存在于用户本地,服务器端并不知道它的存在,也无法使用。所以如果我们要像平时那样使用 localStorage,我们必须控制好只在用户本地使用。如果要在 Nuxt3 里读取 localStorage 里的数据,我建议在 layout 里进行。经我测试,这是我们最初能插入 JS 的位置。

    // <script setup>
    import useStore from '~/store';
    
    const store = useStore();
    // 只有在客户端的时候才执行
    if (process.client) {
      store.init();
    }

    已有解,寻求最优解

    接下来的问题,我的方案能解决,但我不确定是否是最好的方案。所以我也在寻找更好的做法。

    1. useAsyncData 难以打断点

    问题

    useAsyncData 会在服务器端执行,所以在 Devtools 里打断点可能拦截不到。

    解法

    我目前的解法是在里面插入 console.log() ,利用热更新,切换页面,让断点生效。

    2. onBeforeMount 读取 localStorage 会丢失响应式

    版本

    v3.4(新版本待测试)

    问题

    非常诡异。

    我有一个变量 myRate ,因为一些理由,所以要把数据存在 localStorage 。我们知道 nuxt 在服务器端渲染的时候没有 window 对象,所以我就把它放在 onBeforeMount 。

    但是这样就会导致 myRate 丢失响应式,且只在 input className 丢失,非常诡异。

    解决

    我暂时放在 onMounted,虽然会造成页面抖动,但是工作正常。

    问题

    页面中有一个 nuxt-link 生成的 <a> ,点击无效,没有报错,浏览器和开发环境均无报错。

    解决

    实际上是 Vue 模版中某个变量名拼错了,渲染失败。但是不知道为何没有错误信息。找到并修正后,使用正常。

    暂时无解

    使用 route.hash 加载数据的话,SSR 会缺少数据

    当我们请求包含 hash 的地址,route.hash 在服务器端可能为空,导致无法正常启动服务器端渲染。请求会在渲染后再发出,造成界面抖动 CLS。

    解决方案就是不要用 hash 作为数据标记。

    @nuxtjs/i18n no_prefix 策略下,无法 SSR

    版本

    Nuxt@3.5 + @nuxtjs/i18n@8.0.0-beta.12

    问题

    1. 使用 no_prefix 策略
    2. detectBrowserLanguage: false
    3. 没有 SSR,渲染出来的是 key,然后变成目标语言

    Tips

    GET 请求里不能包含 body,否则可能 405

    如果用 useFetch 发起的 GET 请求包含 body/server/api 的接口会报告 405 Method Not Allowed 错误。

    这个问题主要不好排查。


    总结

    开始用 Nuxt 的时候,我没想到会有这么多问题:不就是提前渲染一下模版嘛,能麻烦到哪儿去?实际操作之后,发现很多熟悉的操作都不好处理,比如从 localStorage 里面取数据然后渲染到页面去,就要区分函数执行环境,否则就会报错;要渲染用户相关数据,得考虑服务器运行环境的复杂性,包括网络和多层缓存,不能想当然的使用 cookie 与 token。

    总之,心怀敬畏,持续学习,多看文档。有问题,欢迎提问;有建议,欢迎指教。大家一起进步。

  • 跟大家聊聊当下卖课的现状

    跟大家聊聊当下卖课的现状

    前言

    前阵子偶遇合适的项目,于是又做了一个系列教程:Nuxt3+Vercel+Serverless 数据库全栈开发。发布在两个平台:

    1. B站:Nuxt3+Vercel+Serverless 数据库全栈开发
    2. YouTube:Nuxt3+Vercel+Serverless数据库全栈开发 – YouTube

    具体内容这里不再细述,总之很新很好很强大,性价比很高,推荐大家去看,顺便帮我点赞分享,关注频道。

    写这篇博客是因为有同学问我:为什么不去网课平台好好做?比如网易云课堂、慕课网等,应该蛮挣钱的,说不定还能成为事业。何苦像现在一样苦哈哈的呢?

    考虑到现在年景不好,很多同学都想拓展副业,所以我想简单分享一下目前的卖课环境,供大家参考。

    挣钱么?看看平台分成

    随便点开某云课堂,看着动辄上千的课单价,与几百上千的学员数,简单一乘,一节课能卖大几十万上百万!作为讲师我们难免会心动。但实际上,最后拿到手里的钱可能没你想象的那么多。接下来请听我来讲解。

    假设说,我们与某平台签约,做一套课程,售价人民币壹仟元/套。经过一两个月的努力,课程终于顺利上线,开始售卖。那么每售出一套,我们能挣多少钱呢?

    首先,平台会收取 50% 的服务费,所以到这一步就只剩 500 了。

    如果用户使用苹果设备,那么苹果要收取 30% 的苹果税。平台愿意跟我们分摊,所以就再 -15%,变成 35%。Android 和网页会好一些。

    剩下的 350/500 也不是实时到账,平台为了防止用户退费,会锁定在账户里一段时间。时间据说大约是两个月,之后我们才可以申请提现。提现会有一些打款周期,不太久也不会即时,我们算半个月好了。

    如果我们以个人身份签约,那么平台会直接帮我们交税。通常来说按照劳务费标准,超过 800 的部分 20%,所以此时大约会剩 40% 或者 28%。如果以公司签约,则可以省掉个税,但是要负担其它税费,这里不展开讨论。

    最终,一套 1000 块的课程,卖出去之后,我们能在 2.5 月之后拿到 300~400 。怎么说呢,不算太少;但是考虑做课 2 个月,领钱 2 个月,前后 4、5 个月,这个周期真不算短。如果兼职来做,压力很大。

    (以上知识并未根据累进税率更新,所以仅供参考。)

    做什么内容,谁说的算?

    有的同学想了想,又看了看。那个“Vue2 开发企业后台”卖 ¥500,有1000人买,合 50w;就算 35%,自己也能落 17、18w,分散到 4个月,合每个月 4w+,比自己上班还挣钱,也可以啊!我赶紧去做个 “Vue3开发企业后台”!

    结果很可能会失望,因为平台运营会告诉你:Vue3 已经有人在做了;React 也有人在做了;Svelte?国内都没人用,不准备上这门课。现在缺个 Vue3 + AI 的选题,要不你试试?

    Vue3+AI?这俩不挨着啊,而且我也不会 AI,公司也不用,还得现学。4 个月时间肯定不够,而且,如果到时候质量不达标,怎么办呢?要不我来做个 Nuxt3+Vercel+Serverless 全栈开发吧,我最近做了个项目,拿来当 demo 很合适;而且这套技术栈又高效又不需要启动资金,很适合大家拿来做独立开发和接单。

    运营多半会回复:你这些技术国内用的人很少,而且英文那么多,很多人一看就望而却步,我们的目标用户还是初级开发新人比较多……这个选题也不行。

    总之,如果你是个做课新人,没有成功案例,那么多半接不到热门选题。对你来说成本较低的选题,平台不想要。而分给你的冷门选题性价比如何,就不一定了。

    那我们不理大平台,自己做?

    既然平台不当人,那我们不要理大平台,自己做自己卖!

    也不行,理想很丰满,现实很骨感。如果你不是几十万粉的大 V,自带流量,那么自己做更没戏。

    首先,平台是最大的流量来源。他们收走的 50% 服务费,很大程度上是流量费用,这笔钱其实免不掉。有些云平台支持自主分销,你自己能卖掉,所有钱都是你的,平台根本不担心。

    其次,有些同学,比如我,觉得自己很了解技术潮流,能走在时代前端,所以我做的课一定有价值,能站在技术前沿,越陈越香。但实际上,普通学员根本就不知道我在说什么,也不会买我的课,结局自然是做一套赔一套。什么课最好卖?一定是大平台选出来的那些题目。

    另外还有定价和受众问题。卖课怎么挣钱?

    1. 基础课
    2. 高价
    3. 卖给小白

    三点缺一不可。

    我最初的分享动机是:针对比较新的,有价值的技术做分享,面向一线开发人员,意在给大家一个开箱即用的解决方案。比如哪天各位要开发出海网站产品,把我的 Nuxt3 视频看一遍马上就能上手。用上了,觉得有价值,就打赏百十块,大家都是月入好几万的人,让我日入几百块不是轻轻松松?

    实际执行下来完全不行。因为这些人都很善于发现有价值的内容,也会很积极主动去学习。所以一方面这样的人不多,能找到我的更是凤毛麟角;另一方面大家对付费购买内容的兴趣不大,大部分东西早就学会了,而且有那个钱不如捐几个开源项目。(对,我就是这样……

    谁能找来大量愿意付费的小白?大平台。所以,只有跟着他们才能挣钱。

    能成为稳定的“睡后收入”么?

    有些同学想,即使挣不到大钱,只要每个月稳定给我带来几千块的收入,也很好啊。其实这个也很难。

    我们都会期待网课能长期稳定地给我们带来收入,但实际上,由于 Web 开发技术本身发展就很快,不断有新概念、新技术、新工具涌现出来,所以网课的淘汰速度远比我们想象的要快;再加上不断有新人加入,用新技术做出更多长尾垂直的课程;平台也愿意主推更新的课程。

    综上,一个课程的稳定生命周期可能只有不到一年,能维持在收入高峰期更是只有短短几个月。如果我们辛辛苦苦做几个月,换来月均收入多个几千块,还要做不熟悉、不喜欢的内容,我觉得就划不着了。

    所以,我的建议

    看前面的内容,也知道我大意是劝退。不过呢,我其实支持大家勇于尝试,只是动手之前多考虑考虑,说不定其它方向更适合你。比如说我,其实我也想割韭菜,只不过我看中的韭菜,我割不了😂。我是后来发现挣不到钱,才干脆不挣了,随缘,兴趣使然。

    我建议想做课挣钱的同学、想在这个方向做副业的同学,好好想想:

    1. 是否自带流量,跟平台讨价还价时有议价权
    2. 或者,光环夺目,可以适当变现
    3. 或者,愿意被同行鄙视为割韭菜
    4. 做任何内容都可以,自己感不感兴趣无所谓,挣钱嘛,不寒颤
    5. 超负荷的辛勤劳动换来一个月只能收入几千块

    总结

    我还是会继续分享我想分享的内容,不指望靠分享卖课能实现什么自由。我支持大家都去做想做的事情,合情合理更要合法的挣钱 😊。

    话都说到这儿了,那么,如果大家看到我的内容,觉得有用,不妨打赏一二;大家觉得不好,也请及时稍作点拨。感激不尽。

  • 【视频】Nuxt3+Vercel+Serverless 全栈开发(5):部署到 Vercel+开发统计功能

    【视频】Nuxt3+Vercel+Serverless 全栈开发(5):部署到 Vercel+开发统计功能

    课程继续。仍然结合近期的开发经验,分享最近我比较喜欢的全栈+高效+免费+云原生技术方案。

    https://www.bilibili.com/video/BV16h411N762/ (请 B 站有号的同学帮忙点赞)

    本次课程内容:

    • 将作品部署到 Vercel
    • 使用自定义域名保障国内访问
    • 开发统计功能页面

    终于讲到部署环节了。其实 Vercel 对现代化 Web 全栈开发是非常重要的组成部分,它自带的 Serverless 功能是实现服务器端渲染(SSR)的关键,而且我们也需要使用 Serverless 来完成数据交互。部署到 Vercel 非常简单,点几下就能完成。

    Vercel 官方网站 vercel.com 在中国大陆可以无障碍访问,但是免费提供的二级域名 *.vercel.app 不行。解决方案很简单,自己注册一个域名,然后 CNAME 过去即可。注册域名的选项很多,各大云平台如阿里云、腾讯云均可。自己的小域名如果不提供大规模服务,不备案也可以用。价格大概一年十几块吧。

    然后讲解制作统计页面,主要涉及 Redis 的操作和前后端数据交互。之前埋下的数据结构设计,在此可以更好的演示。

    至此,这个系列基本连载完成。从技术选型、到项目搭建、到前后端开发、到最终部署上线,都覆盖到了。其它想讲的内容还有很多,不过都属于锦上添花,对于有开发经验的同学来说,相信现在已经可以动手。未来当然会继续深入,把统计功能加强一些,把关系型数据库也纳入进来。进阶课也在规划中,比如面对内容更庞大的网站,这个项目中太过简单的数据交互、缓存处理、SEO 都不够用,需要进阶强化。敬请期待吧。

    本周正好端午节,休息一周,周三(6月21日)晚上直播答疑,欢迎围观。


    这期视频也剪得很细,还做了字幕,希望大家能学到东西。

    如果你有任何问题、建议,欢迎留言讨论。请 b 站有号的同学帮忙分享完播一键三连,谢谢大家。

    另外,我也在 YouTube 上上传了一份,大家有空的话,麻烦帮忙关注下我的油管频道,感谢感谢。肉山全栈小课堂 – YouTube

  • 记一次 TiDB Cloud Serverless 超额导致的博客超时故障

    记一次 TiDB Cloud Serverless 超额导致的博客超时故障

    今天早上起来,习惯性地刷新博客统计页面,发现 502。这可不妙,好不容易我坚持到现在终于有点流量,于是赶紧想办法修复。

    博客基础架构

    我的博客架构大体是:

    • 小主机,本地跑 php8.2-fpm 和 nginx
    • 使用 nginx 代理提供服务
    • 数据库使用 TiDB Cloud Serverless
    • 外面套上腾讯云 CDN

    仔细一看,错误页面的 Nginx 是 1.18.0,正是我服务器上的版本,貌似是本地上游 php-fpm 的问题,不是腾讯云 CDN 的问题。ssh 登录服务器,基本正常,验证了判断。查看错误日志,tail /var/log/nginx/blog-error.log,大量的 upstream 错误。top 查看进程负载,服务器本身很闲,但是 5 个 php-fpm 进程虽然不忙,但是都跑了很久。

    重启治百病,先升级系统

    以前没见过这种情况,本着遇事不决先重启的思路,我想先升级重启试试。于是 apt update & apt upgrade 升级系统,接着 reboot。停了一会儿打开网页还是不行。

    登录服务器 service --status-all 查看服务,貌似都正常。查看博客服务器的配置文件,也没写错。输入 service nginx restartservice php8.2-fpm restart 重启服务,还是不行。

    然后 Google PHP8.2、php-fpm、502 等关键词,限制最近一周,看看会不会是新版本引入了新 bug。没有找到结果,应该也不是。

    会不会是 TiDB Cloud 没钱了?

    看过前面博客:💪 WordPress 使用 TiDB Cloud 替换 MySQL 💪 的同学可能知道,我不久前把博客从本地 MySQL 迁移到了 TiDB Cloud Serverless。会不会是欠费停机了?我觉得不应该呀,免费额度 5GB,我的博客数据库前几天看过才区区 300+MB,不会突然就突破限制。

    不过我还是打开了 TiDB Cloud,姑且看一眼吧。没成想,果然是 TiDB Cloud 额度用完了,不过不是容量问题,而是 RU(Request Units,请求单位,TiDB 的某个计费单位)超限。TiDB Serverless Tier 每个月有 50M 的免费 RU 额度,我当时已经用掉 59.6M,所以被停止服务了。

    不过这里有个问题:我的 php-fpm 整个被卡死了,因为 TiDB Cloud 没有及时断开连接,导致我的 PHP 一直在等待数据库响应,但实际上数据库是不会响应的,相当于我的 PHP 线程都在守活寡。直到超时,才得到解脱。这样一来,我的服务器也无法响应任何其它 PHP 请求,包括 phpinfo() 等未使用 TiDB Cloud,甚至那些只有简单 PHP 功能的请求。

    按理说我超额,他们应该拒绝连接,让我看到数据库连接失败的错误,而不是卡住我直到超时。这样一来,

    1. 至少我的服务器还可以响应别的 PHP 请求
    2. 有了数据库连接失败的错误提示,我也能尽快找到问题根源。

    上调预算

    TiDB 还是蛮大方的,不需要预付款、预充值,只要将来按用量结账即可。于是我把预算上调到 $5/月,然后,重启了服务器。结果,又发生了第二个意外。

    我以为上调预算之后,连接、请求就能恢复,结果没有,还是白屏。而且,从 TiDB Cloud 的统计页面来看,在上调预算之后,数据库经历了一大波密集的请求:

    直到约 30 分钟之后,我的博客才渐渐缓过来,我也才有机会写这篇复盘文章。

    我不太确定这波请求是哪里产生的,是我的博客还是 TiDB 的网关,这个有待进一步研究学习。

    请教 TiDB 大佬

    我带着问题在推上请教了大 V 能哥。他告诉我,按照目前的产品策略,超额用户也可以以很低的频率访问数据库,因为有人是占了太多空间,需要有机会让他删数据。

    那这就是彼之蜜糖,吾之砒霜了。我的情况是存储量少(不到400mB),但是请求数高(我看的时候为 60M),所以除非调高预算,我不存在继续使用的可能性。但是他们又不会拒绝我的服务,于是就变成了我服务器上的 php-fpm 被卡死在连接数据库阶段,无法响应任何 PHP 请求。

    我把这个问题反馈给了 TiDB 的社区工作人员,期待他们能解决这个问题。

    下一步:解决方案

    这次故障的修复过程对我来说还是挺新鲜的,也还算顺利。给我在系统设计领域提供了新的经验,所以我拿出来分享给大家。

    不过话说回来,从白嫖的角度来看,迁移到 TiDB Cloud Serverless Tier 上似乎不是很明智。按照 WordPress Jetpack 的统计,我现在每月访问量大约是 7k UV,10k PV,如果这个级别就要花钱,而且动辄几刀的话,那我可能还是迁回去用本地数据库好一些。

    当然,解决方案还是有的。

    首先,Serverless Tier 可以创建多个节点,每个账号的最初的 5 个节点都有 5GB 空间+50M RUs/M 的免费用量。所以我可以写一个自动化脚本,每周将数据同步到下一个节点,然后自动修改链接类到新的节点。嘿嘿嘿,不知道这样的作品能不能参加 Hackathon 😂😂

    其次,好好查查 slow sql,找找优化点。减少每次请求产生的 RU 消耗。

    再次,升级 CDN 配置。我目前的网页都是 30d 缓存,按理说不应该有很多消耗才对。后台只有我一个人在用,不应该有很多数据库访问。我怀疑还是这块儿没搞好。应该有不小的优化空间。

    总结

    TiDB 正在举办新一年的 Hackathon,我也厚着脸皮去要了 $100 的赞助,白嫖大业应该还能再坚持一段时间。如果你也对数据库应用开发感兴趣,我强烈推荐你也来参加这次 Hackathon:【TiDB Future App Hackathon 2023 】TiDB 首届全球黑客马拉松,开发者的狂欢夏日盛会!快来一起 Coding 吧!这次 Hackathon 针对应用层,基本上使用 TiDB Cloud Serverless 就可以,适合各个领域的开发者参加。

    无论如何,感谢 TiDB 提供给我们免费、好用的数据库产品,也推荐大家使用 TiDB Cloud Serverless。如果大家有什么意见建议,欢迎留言讨论。

  • 【视频】Nuxt3+Vercel+Serverless 全栈开发(4):投票接口+数据处理+了解服务器端渲染

    【视频】Nuxt3+Vercel+Serverless 全栈开发(4):投票接口+数据处理+了解服务器端渲染

    课程继续。仍然结合近期的开发经验,分享最近我比较喜欢的全栈+高效+免费+云原生技术方案。

    本次课程内容:

    • 创建 Post 接口,完成投票
    • 显示投票结果数据
    • 了解服务器端渲染

    我们先利用 Nuxt3 的路由机制,创建 /api/rate.post.ts 接口,用来处理用户投票,将数据记录进入 Redis 数据库的动作。

    为了保证数据安全,我每次会写入两次数据,一个键值是 $$$_{uid},主 key,用来日常显示;另一个键值是 {uid}_{小时},用来备份。这样假如某些情况下我们的投票系统被攻击,也能快速会滚到最近一小时的数据。并且这个备份频率也可以按需调整。

    然后我们在前端使用 $fetch 方法调用接口完成投票。并介绍了计算成绩的逻辑。

    最后介绍了 SSR 的结果,这样就能解释,为什么我们要使用 Nuxt3 内建的 useAsyncDatauseFetch 而不是平时常见的远程请求库手动请求。

    这期视频也剪得很细,还做了字幕,希望大家能学到东西。

    如果你有任何问题、建议,欢迎留言讨论。请 b 站有号的同学帮忙分享完播一键三连,谢谢大家。

    另外,我也在 YouTube 上上传了一份,大家有空的话,麻烦帮忙关注下我的油管频道,感谢感谢。肉山全栈小课堂 – YouTube

  • 鸣谢各位老板舰长赞助商

    鸣谢各位老板舰长赞助商

    想来想去,决定开个页面用来供奉各位支持过我的老板。

    赞助我,让我贡献更多内容吧!

    • 有了赞助,我会有更高的热情输出各种内容
    • 可以在我的各种内容里获得致谢
    • 可以定制感兴趣的内容
    (更多…)