10 行代码,实现请求代理

代码展示

不是标题党,直接上代码 :

export default async function(req: Request): Promise<Response> {
  return fetch("https://github.com/login/oauth/access_token", {
    method: "POST",
    headers: req.headers,
    body: req.body,
  });
}

之后每次调用 https://github.com/login/oauth/access_token 接口时,把 API 地址换成我们的服务器地址,即可完成对该接口的代理。

背景

使用 Github OAuth 授权流程的小伙伴一定不陌生,整个流程分为 3 步:

  1. 客户端:浏览器重定向到 Github 授权页面。
  2. Github 重定向:用户授权后,Github 重定向到我们的服务端并携带 code 参数。
  3. 服务端:拿着 code 调用 Github 的 /login/oauth/access_token 接口,获取 access_token

拿到 access_token 后,就可以用它调用 Github 的 API 服务了。

由于国内现状,Github 对于我们来说是不可能畅通无阻的访问的。

这里存在两个需要考虑的网络环境:客户端、服务端。

客户端即用户的网络我们无法控制,网络不行就没法重定向到 Github 的网页。

如果你的产品受众人群不具备访问 Github 的能力,那还是添加一些诸如邮箱、密码、微信扫码登录对国内用户友好的登录方式。

而对于后者服务端的网络,由于我的服务器位于境内,所以也存在无法畅通连接 Github 服务的问题。

为了解决这个问题,一种方案是在服务器上安装一些代理应用,但是仅仅只是为了保证 https://github.com/login/oauth/access_token 这一接口能连通就安装代理应用,有点小题大做了,那可不可以仅仅实现这一个接口的代理?

带着这一目的,我调研了一些提供 FasS(Function as a Service)的云服务,很快写出了上面的代码,经过实际验证,确实是可行的。

技术解析

实现接口代理功能只需几行代码,简单强大,这受益于 Web 标准的不断普及。

这背后有一个名为 WinterCG 的区组织,他们主要的工作是推动跨平台 JavaScript 运行时环境中的 Web API 标准化。

——WinterCG 组织的参与者

WinterCG 核心目标之一,就是在各种非浏览器环境中(Node.js、Deno、边缘计算等)提供一致的标准,使开发者可以在不同的运行时中使用相同的 API 构建应用。

Fetch API 就是其中之一,它支持的对象有:fetch Response Request Headers 等。

只要运行环境支持这些标准,上述代码就可以正常运行。

fetch() 可以接收来自 Request 对象的 headersbody ,并且直接返回 Promise<Response> 非常简洁方便。

接下来,我们通过 Express 结合 fetch 实现相同的代理功能来感受下它的不同。

const express = require('express');
const fetch = require('node-fetch');

const app = express();

// 解析 JSON 请求体
app.use(express.json());

app.post('/proxy', async (req, res) => {
  // 发送请求到 GitHub OAuth 端点
  const response = await fetch('https://github.com/login/oauth/access_token', {
    method: 'POST',
    headers: req.headers, // 使用客户端请求中的 headers
    body: JSON.stringify(req.body), // 将请求体转为 JSON 字符串发送
  });
  // 读取响应并返回给客户端
  const data = await response.json();
  res.json(data);
});

app.listen(3000, () => {
  console.log('Server running on <http://localhost:3000>');
});

通过 Express 实现相同功能显然代码量更多,并且需要处理一些潜在的兼容性问题。例如,如果代理接口返回中含有 Transfer-Encoding: chunked,再用 response.json() 处理响应就会出现错误。

而使用 fetch() 直接返回响应对象的方式则不需要关心这些细节,它能自动处理这些复杂情况。

此外,使用 fetch() 发送请求时,请求头中的 Host 会自动的根据请求地址设置正确的值,并且不允许我们手动设置,可见: MDN: 禁止修改的标头

在代理接口应用场景中,传入的请求头中的 Host 即为我们代理服务器的 host 地址,如果没有 fetch API 自动帮我们设置正确的 Host ,请求是一定会失败的。

这一点也是我在用 Rust 实现相同的代理功能时发现的,可见标准化 Web API 为我们省了多少麻烦。

应用在 auth.js 中

auth.js 是 JavaScript 生态中最为流行的身份验证库,可快速接入众多第三方身份验证服务商(如 Google、Github、Gitlab 等)。

下面代码展示了如何使用代理 API 获取 Github Token:

import { NextAuthConfig } from 'next-auth'
import GithubProvider from 'next-auth/providers/github'

const githubProvider = GithubProvider({})
// 有代理优先使用代理
githubProvider.token = process.env.FETCH_GITHUB_TOKEN_PROXY || githubProvider.token

export const authConfig = {
	providers: [githubProvider],
	session: { strategy: 'jwt' },
	// ...
} satisfies NextAuthConfig

通过这种方式,可以将代理服务用在 auth.js 中用来获取 Github Token。

总结

在现代 Web 开发中,标准化的 API 让我们的开发流程变得更加简单高效。通过 fetch 等标准的 Web API,跨平台的运行时环境可以一致地处理网络请求、响应等操作,大大减少了代码的复杂性。

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值