如何在Deno中获取客户端的IP地址?
我已经使用标准的http
库创建了一个测试服务器,但是我无法找到一种提取客户端IP的方法。我需要作为一个安全功能,以防止多次提交。
在NodeJS/Express中,
request
对象有一个相同的request
属性。req.ip
在Express中给出了我想要的东西,但是在Deno中它相当于什么呢?
我的代码是:
import { serve } from "https://deno.land/std@0.125.0/http/server.ts";
serve(
(req) => {
console.log(/* the client IP */);
return new Response("hello");
},
{ port: 8080 }
);
是否还有其他方法来防止来自同一设备的多个访问?
谢谢
发布于 2022-02-06 20:18:19
以一种类型安全的方式来完成这个任务有点复杂,因为serve
的类型是这样的。首先,我将向您展示一个如何执行该操作的示例,然后我将解释后面的类型。
示例
example.ts
import {
serve,
type ConnInfo,
type Handler,
type ServeInit,
} from 'https://deno.land/std@0.125.0/http/server.ts';
function assertIsNetAddr (addr: Deno.Addr): asserts addr is Deno.NetAddr {
if (!['tcp', 'udp'].includes(addr.transport)) {
throw new Error('Not a network address');
}
}
function getRemoteAddress (connInfo: ConnInfo): Deno.NetAddr {
assertIsNetAddr(connInfo.remoteAddr);
return connInfo.remoteAddr;
}
const handler: Handler = (request, connInfo) => {
const {hostname, port} = getRemoteAddress(connInfo);
const message = `You connected from the following address: ${hostname}`;
return new Response(message);
};
const init: ServeInit = {port: 8080};
serve(handler, init);
console.log(`Listening on port ${init.port}...\nUse ctrl+c to stop`);
类型
查看serve
函数的文档,您可以看到它接受两个参数:Handler
类型的回调和ServeInit
类型的一些选项。
async function serve(handler: Handler, options?: ServeInit): Promise<void>;
Handler
回调接受两个参数:一个Request
和一个ConnInfo
类型的对象。
type Handler = (request: Request, connInfo: ConnInfo) => Response | Promise<Response>;
ConnInfo
看起来是这样的:
interface ConnInfo {
readonly localAddr: Deno.Addr;
readonly remoteAddr: Deno.Addr;
}
应该具有远程IP地址的部分(从技术上讲,它是远程主机名,但很可能是IP地址,除非您在服务器环境中配置了自定义DNS设置)是connInfo.remoteAddr
的对象,它的类型为Deno.Addr
,如下所示:
// in the Deno namespace
type Addr = NetAddr | UnixAddr;
--这是它变得复杂的地方。 Deno.Addr
是一个歧视结合 of Deno.NetAddr
和Deno.UnixAddr
(这意味着它可能是其中之一),而属性transport
用于区分两者。
// in the Deno namespace
interface NetAddr {
hostname: string;
port: number;
transport: "tcp" | "udp";
}
interface UnixAddr {
path: string;
transport: "unix" | "unixpacket";
}
net地址具有hostname
属性(其值为IP地址)和port
属性,而unix地址具有path
属性。
监听程序是在内部创建的,用于支持服务器实际上只监听TCP,因此我认为可以安全地假定远程地址将是一个网络地址。但是,由于Handler
回调参数在serve
函数中的类型签名不显式(尽管应该如此!),所以TypeScript不知道这一点。
所以,在以一种类型安全的方式访问网络地址(而不是unix地址)之前,应该由程序员确保地址实际上是一个净地址。这就是类型断言函数 assertIsNetAddr
发挥作用的地方。(类型断言执行运行时测试,从而向编译器提供条件的“保证”:如果条件无法保证,则抛出异常。)因为作为程序员,您已经比TypeScript编译器了解更多(地址在TCP上,并且将是一个网络地址),所以您可以断言该地址确实是一个网络地址。然后编译器将允许您使用该地址作为净地址。
如果您想在地址不是净地址的情况下抛出错误:可以在代码中使用类型谓词作为条件,而不是断言函数。
这里有一个链接到TypeScript游乐场,我在那里创建了一个游乐场,其中包含了示例中使用的类型,这样您就可以探索/实验了。
最后,(,这不是类型安全的)如果您只想在没有检查的情况下使用值(因为您已经完成了您的研究,并且确信您永远不会处理非TCP连接,那么您可以简单地使用类型断言。
const handler: Handler = (request, connInfo) => {
const {hostname, port} = connInfo.remoteAddr as Deno.NetAddr;
const message = `You connected from the following address: ${hostname}`;
return new Response(message);
};
https://stackoverflow.com/questions/71008150
复制相似问题