有没类似得demo啊, 求大佬给一个
import { copy, readerFromStreamReader} from "https://deno.land/std/streams/mod.ts";
// fetch 远程图片
const response = await fetch("https://deno.com/deploy/logo.png");
// 打开本地文件
const file = await Deno.open("./logo.png", { create: true, write: true });
// 从 response 创建可读流
const reader = readerFromStreamReader(response.body!.getReader());
// 将可读流 copy 到 file 中
await copy(reader, file);
// 关闭文件
file.close();
运行:
deno run --allow-net --allow-write fetch.ts
不使用 steam 的方法:
const response = await fetch("https://deno.com/deploy/logo.png");
const buffer = await response.arrayBuffer();
await Deno.writeFile("./logo.png", new Uint8Array(buffer));
- Stream 方式:一边 fetch 一边写入文件(如果服务器支持)
- 普通方式:先 fetch,保存到内存,然后一次性 write 到文件
1 个赞
好详细, 非常感谢
stream 的方式走response好像不太对, 不知道咋写啦
import { serve } from "https://deno.land/std@0.119.0/http/server.ts";
import { readerFromStreamReader} from "https://deno.land/std/streams/mod.ts";
const respOpt = {
status: 200,
headers: {
"content-type": "image/png",
},
}
async function handleRequest(request) {
const { pathname } = new URL(request.url);
const response = await fetch('https://deno.com/deploy/logo.png')
if (pathname.startsWith("/pic")) {
const fileBuf = await response.arrayBuffer()
return new Response(new Uint8Array(fileBuf), respOpt);
}
if(pathname.startsWith('/img')) {
const reader = readerFromStreamReader(response.body?.getReader());
// Stream方式, 应该怎么写呀,
return new Response(reader, respOpt);
// request.respondWith(
new Response(reader, respOpt)
)
}
}
console.log("Listening on http://localhost:8000");
serve(handleRequest);
fetch拿到之后, 怎么pipe/copy到response里去呀
import { readableStreamFromReader } from 'https://deno.land/std@0.119.0/streams/conversion.ts';
import { readerFromStreamReader } from "https://deno.land/std/streams/mod.ts";
import { fromFileUrl } from 'https://deno.land/std@0.119.0/path/mod.ts';
const server = Deno.listen({ port: 8080 });
console.log('chat server starting on :8080....');
const respOpt = {
status: 200,
headers: {
'content-type': 'image/png',
},
};
async function requestHandler(req) {
const response = await fetch('https://deno.com/deploy/logo.png');
const pathname = new URL(req.request.url).pathname;
console.log(pathname,'pathname')
if (pathname == '/img') {
// 这部分咋写呀, 有可行方案嘛
const reader = readerFromStreamReader(response.body?.getReader());
req.respondWith(new Response(reader, respOpt));
}
if( req.request.method === "GET" && pathname === "/favicon.ico") {
req.respondWith(Response.redirect("https://deno.land/favicon.ico", 302));
}
if (pathname == '/pic') {
const u = new URL("./logo.png", import.meta.url);
const file = await Deno.open(fromFileUrl(u));
req.respondWith(
new Response(readableStreamFromReader(file), respOpt),
);
}
}
for await (const conn of server) {
(async () => {
const httpConn = Deno.serveHttp(conn);
for await (const requestEvent of httpConn) {
requestHandler(requestEvent);
}
})();
}
直接 return
就行了啊。fetch 的结果就是 Response
对象。
safe-newt-12 - Deploy Playground (deno.com)
import { serve } from "https://deno.land/std@0.119.0/http/server.ts";
// deno-lint-ignore no-unused-vars
async function handler(request: Request): Promise<Response> {
return await fetch("https://deno.com/deploy/logo.png");
}
console.log("Listening on http://localhost:8000");
serve(handler);
1 个赞
nice, 没想到能这么简单
1 个赞
我特意标准了类型,handler
函数返回一个 Promise<Response>
,而 fetch 的类型就是:
function fetch(input: Request): Promise<Response>
恰恰返回了一个 Promise<Response>
,所以,直接把 fetch 的返回值 return 就行了。其实,async/await 可以直接去掉的。
另外,handler 的参数是 Request
,fetch 的参数也是,所以如果我们想做一个代理服务的话,也是非常简单的。
试了一下这个return fetch做http代理的操作, 发现可行, 不过好像只能走通http请求
curl.exe -x localhost:8000 http://httpbin.org/get?a=1 -v
跑不通https的
curl.exe -x localhost:8000 https://httpbin.org/get?a=1 -v
用tcp应该能实现 https请求的代理, 不过也失败啦, 好像是在最后互相copy阶段出现的问题, 懵p了又
// curl.exe -x localhost:8000 https://httpbin.org/get?a=1 -k -v
const listener = Deno.listen({ port: 8000 })
console.log('http://localhost:8000/')
function parseHeaders (headers) {
var arrhs = headers.split('\r\n'),
arrh1 = arrhs[0].split(' '),
method = arrh1[0].trim(),
arrPath,
host,
port
if (method == 'CONNECT') {
arrPath = arrh1[1].split(':')
host = arrPath[0]
port = arrPath[1] || 443
} else {
arrPath = arrhs[1]?.split(' ')[1].split(':')
host = arrPath[0]
port = arrPath[1] || 80
}
return [method, host, port]
}
for await (const conn of listener) {
;(async () => {
let buf = new Uint8Array(4096)
let n = (await conn.read(buf)) || 0
if (n == 0) return
buf = buf.slice(0, n)
let headers = new TextDecoder().decode(buf)
console.log(headers)
if (!headers.includes('\r\n\r\n')) return
let [method, host, port] = parseHeaders(headers)
console.log(method, host, port)
const isTls = method == 'CONNECT'
let connect = isTls ? 'connectTls' : 'connect'
var remote = await Deno[connect]({
hostname: host,
port,
transport: 'tcp'
})
if (isTls) {
let head =
'HTTP/1.1 200 Connection established\r\nConnection: close\r\n\r\n'
await conn.write(new TextEncoder().encode(head))
} else {
await remote.write(buf)
}
Deno.copy(conn, remote)
await Deno.copy(remote, conn)
// 似乎是这里出了问题, 也是可以走通http的请求, 跑不通https的请求
})()
}
访问 http://localhost:8000
会全站镜像 github:
import { serve } from "https://deno.land/std@0.120.0/http/server.ts";
import { blue } from "https://deno.land/std@0.120.0/fmt/colors.ts";
const FROM = "http://localhost:8000";
const TO = "https://github.com";
async function handleRequest(request: Request): Promise<Response> {
const url = request.url.replace(FROM, TO); // 原 url 替换为代理 url
const response = await fetch(url);
const headers = new Headers(response.headers);
headers.set("x-proxy-by", "xxx");
headers.set("x-custom", "yyy");
const body = (await response.text()).replaceAll(TO, FROM);
return new Response(body, { headers });
}
console.log(`Proxy ${blue(FROM)} to ${TO}`);
serve(handleRequest);