在 Deno 中获取远程客户端 IP 地址
Get remote client IP address in Deno
如何在 Deno 中获取客户端的 IP 地址?
我已经使用标准 http
库创建了一个测试服务器,但我想不出提取客户端 IP 的方法。
我需要它作为防止多次提交的安全功能。
In NodeJS/Express there is an ip
property of the request
object that does the same.
req.ip
gives the thing I want in Express but what is it's equivalent in 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 }
);
是否有任何其他解决方法来防止从同一设备进行多次访问?
谢谢
由于 serve
的输入方式,以 type-safe 的方式执行此操作有点复杂。首先,我将向您展示如何操作的示例,然后我将解释类型。
例子
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
function, you can see that it accepts two parameters: a callback of type Handler
, and some options of type ServeInit
的文档:
async function serve(handler: Handler, options?: ServeInit): Promise<void>;
Handler
callback accepts two parameters: a Request
, and an object of type ConnInfo
:
type Handler = (request: Request, connInfo: ConnInfo) => Response | Promise<Response>;
ConnInfo
看起来像这样:
interface ConnInfo {
readonly localAddr: Deno.Addr;
readonly remoteAddr: Deno.Addr;
}
应该具有远程 IP 地址的部分(从技术上讲,它是远程主机名,但除非您在服务器环境中配置了自定义 DNS 设置,否则它很可能是 IP 地址)是 [=26 处的对象=],它(你可以在上面看到)是 Deno.Addr
类型,它看起来像这样:
// in the Deno namespace
type Addr = NetAddr | UnixAddr;
这就是它变得复杂的地方。 Deno.Addr
是 discriminated union 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";
}
网络地址有 hostname
属性(其值将是 IP 地址)和 port
属性,而 unix 地址有 path
属性.
listener which is created internally to support the server is actually only listening on TCP, so I think it's safe to assume that the remote address will be a net address. However, because the type signature of the Handler
callback parameter in the serve
函数没有明确说明(尽管它应该!),TypeScript 不知道。
因此,作为程序员,您需要确保该地址实际上是一个网络地址,然后才能访问网络地址(而不是 unix 地址)上的属性 type-safe 方式 。这就是 type assertion function assertIsNetAddr
发挥作用的地方。 (类型断言执行运行时测试,从而为编译器“保证”条件:如果无法保证条件,则抛出异常。)因为作为程序员,您已经比 TypeScript 编译器了解更多(即地址在 TCP 上并且将是一个网络地址),您可以断言该地址确实是一个网络地址。然后编译器会允许你使用该地址作为网络地址。
If you want to do something besides throwing an Error in the case that the address is not a net address: instead of an assertion function, you can use a type predicate as a condition in your code.
Here is a link 到 TypeScript Playground,我在其中使用我的示例中使用的类型创建了一个游乐场,因此您可以 explore/experiment.
最后,(这不是 type-safe)如果您只想使用没有检查的值(因为您已经完成研究并且确信你永远不会处理 non-TCP 连接,你可以简单地使用 type assertion:
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);
};
如何在 Deno 中获取客户端的 IP 地址?
我已经使用标准 http
库创建了一个测试服务器,但我想不出提取客户端 IP 的方法。
我需要它作为防止多次提交的安全功能。
In NodeJS/Express there is an
ip
property of therequest
object that does the same.req.ip
gives the thing I want in Express but what is it's equivalent in 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 }
);
是否有任何其他解决方法来防止从同一设备进行多次访问?
谢谢
由于 serve
的输入方式,以 type-safe 的方式执行此操作有点复杂。首先,我将向您展示如何操作的示例,然后我将解释类型。
例子
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
function, you can see that it accepts two parameters: a callback of type Handler
, and some options of type ServeInit
的文档:
async function serve(handler: Handler, options?: ServeInit): Promise<void>;
Handler
callback accepts two parameters: a Request
, and an object of type ConnInfo
:
type Handler = (request: Request, connInfo: ConnInfo) => Response | Promise<Response>;
ConnInfo
看起来像这样:
interface ConnInfo {
readonly localAddr: Deno.Addr;
readonly remoteAddr: Deno.Addr;
}
应该具有远程 IP 地址的部分(从技术上讲,它是远程主机名,但除非您在服务器环境中配置了自定义 DNS 设置,否则它很可能是 IP 地址)是 [=26 处的对象=],它(你可以在上面看到)是 Deno.Addr
类型,它看起来像这样:
// in the Deno namespace
type Addr = NetAddr | UnixAddr;
这就是它变得复杂的地方。 Deno.Addr
是 discriminated union 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";
}
网络地址有 hostname
属性(其值将是 IP 地址)和 port
属性,而 unix 地址有 path
属性.
listener which is created internally to support the server is actually only listening on TCP, so I think it's safe to assume that the remote address will be a net address. However, because the type signature of the Handler
callback parameter in the serve
函数没有明确说明(尽管它应该!),TypeScript 不知道。
因此,作为程序员,您需要确保该地址实际上是一个网络地址,然后才能访问网络地址(而不是 unix 地址)上的属性 type-safe 方式 。这就是 type assertion function assertIsNetAddr
发挥作用的地方。 (类型断言执行运行时测试,从而为编译器“保证”条件:如果无法保证条件,则抛出异常。)因为作为程序员,您已经比 TypeScript 编译器了解更多(即地址在 TCP 上并且将是一个网络地址),您可以断言该地址确实是一个网络地址。然后编译器会允许你使用该地址作为网络地址。
If you want to do something besides throwing an Error in the case that the address is not a net address: instead of an assertion function, you can use a type predicate as a condition in your code.
Here is a link 到 TypeScript Playground,我在其中使用我的示例中使用的类型创建了一个游乐场,因此您可以 explore/experiment.
最后,(这不是 type-safe)如果您只想使用没有检查的值(因为您已经完成研究并且确信你永远不会处理 non-TCP 连接,你可以简单地使用 type assertion:
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);
};