🌈 跨域任意门
PS: 跨域警告是浏览器安全的很重要机制,代理和转发服务对于服务提供者是异常访问行为,如果对目的服务器故意隐藏来源也是一种非法行为。所以虽然没有法律明确,但是需要遵循不能大规模流量劫持,不能从事非法活动,必须添加Origin
或者X-Requested-With
来声明来源等绅士条款。本文部署的服务也遵循了这个限制。
很多时候的小的个人项目需要一些数据,比如自己的魔镜项目添加天气信息、个人工作流收集外链和标题功能、墨水屏时钟添加穿衣指数等信息。因为是开发或者个人需求,所以只需要很少的请求公开的服务数据,比如天气网、解析 HTML 等,即时现在云函数很方便,但是也不值当收集或者搭建服务。
于是就想着直接从客户端请求,但是大部分的服务都有跨域问题,常见的解决方案是服务器简单转发代理一下,今天把这种方案整理一下,做成服务方便自己个人使用,很不值得说,就当是记录了。
能够满足偶尔使用,但是因为是外国友人部署的,服务不太稳定,一个 2kB 的数据请求时间慢的话就要 5s,毕竟数据从客户端到国外代理到国内回到国外最后返回客户端,体验经常出现问题。
好在开源服务,完全可以在自己的服务器上搭建,但是自己搭建还要维护,毕竟哪天服务宕机不知道,时间长了也会忘记,所以不敢开坑~~
不过转念一想,就是一个简单的转发服务,也不要存储、也不需要状态、最多加个鉴权,所以用 serverless 就完全可以满足,于是开搞。
最后效果改进很多,3.62s -> 157ms,请求能百毫秒级返回,体验要好太多。
代理和转发都是描述整个实现的,实际上的处理也就是针对 HTTP 的改造而已,毕竟 HTTP 协议都是基于文本的,实现上也是包装请求和响应,需要修改的也就是 header 那些字段,把代理人同时当服务端和客户端。整个过程很像是:
- 拿到客户端的请求
- 拿到 headers 和 query data,根据需要处理这些数据
- 带着这些 数据 向真实目标发送这个请求
- 拿到真实服务的响应,根据需要处理 response 的 header 和 data
- 返回给客户端
这里也能看到,如果转发的是没有特别加密的数据,那么就算是 SSL 中间代理也完全是能够拿到全部的数据的。
这也是不要用非可信代理的原因,也是我不把我这个代理展示出来的原因。
Proxy 一般都和 Proxy Server 一起说,毕竟必须是一个服务才能称之为 http/ws 代理,本质上说白了也都是转发请求,中间人拿到请求,根据行为目标,可以是有状态或者无状态的。
我上面说的
cors-anywhere
主要使用到了 node-http-proxy 的库,大概翻了一下 node-http-proxy 的代码,因为还涉及到 ws 和 server 的东西,抛出去之后也就两个文件 web-income.js
和 web-outcome.js
没几行代码,处理了很多边界条件,但是里面最终调用的也是 http/https 包,额外处理了 redirect、以及 headers
x-forwarded
host
和 cookies 等内容。代理服务器已经有很多现成的轮子了,nginx 简单配置下就能实现,node-http-proxy 也不需要几行代码,但是这些前提都是 server 需要运行服务,监听端口,而我只想要一个简单的 serverless 就行。
所以最简单的就是一个请求转发函数就行了,网关拿到我的请求,调起我的云函数,云函数获得目标 url 和参数等,向目标 url 发送请求,获得响应,将响应返回给客户端。
- 用腾讯云的 SCF 和 网关服务,不用搭建服务的部分,配置完直接能拿到参数
- 用 node-fetch 作为服务端的请求部分
- 客户端的 headers 过滤处理后作为 request header 请求目标
- 目标返回的内容,header 会过滤,然后原封不同返回客户端
- 不支持 cookies 的状态
- 去除跨域限制
- 请求的内容编码声明,在较新的浏览器已经增加了
Accept-Encoding: gzip, deflate, br
,用 node-fetch 转发收到 br 编码数据会出现乱码,需要处理。 - 腾讯云函数的 Nodejs 环境,安装依赖需要全部上传,但是 node_modules 需要放到 src 里面,src 里面的内容才会被全部上传,此处我谢谢官方开发。
- content-encoding 不能返回到客户端,影响云函数的集成响应机制,也就是云函数会自动处理这个压缩,不能指定。
- Host 和 Origin 的处理
- 在云函数中新建
- 使用 event 数据,拿到 url 和 headers
- 发送请求,拿到响应
- 处理响应,返回给客户端
- 添加触发方式为 API 网关触发
- 部署到发布环境
- 在 API 网关修改路径、设置自定义域名
- 正常提供服务
不得不说腾讯云的解决方案太多了,导致开发体验真的一言难尽:
- 腾讯云的文档写的是真的很差,要想弄明白一个入参和返回类型这么重要的参数,愣是要翻好多页才能在角落里找到一个不准确的实例,在线编辑、线下开发、自动安装依赖这几个概念咱能弄统一不?连个项目根目录都不确定是哪个!! node_modules 需要放到 src 里面才会被部署,src 里面的内容才会被全部上传,这么重要的点不说明一下吗,我愣是弄了一晚上才碰对?(你们鼓捣出来这些东西感觉也是大概率没有开发文档的吧,所以写了一大堆文字教别人怎么用,解释了很多,很贴心的附带了很多的示例代码,但是没有关键的参数和数据类型,代码也都是不准确的,开发者用起来真的很不放心啊。)
- 产品关联,腾讯云的这一套操作需要很多的概念、跳转点击,光这一个服务网关、域名解析、证书、云函数,我想要自定义域名这一个开发流程上结束的功能,也是找了一会才发现在哪。
- 这个东西如果 toB 也许没问题,因为如果公司选择了腾讯云,大概率会深入研究总结出很多流程。但是个人开发者需要这个服务就上手做,结果很多东西并没有看上去那么方便。
感谢您的阅读,本文由 Ubug 版权所有。如若转载,请注明出处:Ubug(https://ubug.io/blog/core-anywhere)