判定按状态码白名单而不是只认 200:探测不带鉴权,OpenAI 回 401、Anthropic 回 405 才是正常应答,说明 TLS 握手、路由、目标服务全都正常。清单和白名单照 sub2api 的 代理质量检查抄来。 失败文案不照抄 Bun:本机端口没人监听时它给的是「Unable to connect. Is the computer able to access the url?」,把矛头指向目标网址,而真正的原因在本机。 对话框留在 InboundDetail 而不是提到 RouterPage——它不写配置文件也不改内核状态, 不需要走那条 commit 链路。firstPort 挪进 shared/inbounds.ts,两个页面都要用它了。
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
* 两半的反馈方式必须不一样。它们长得一样的时候,用户分不清哪个动作要等、哪个不用。
|
||||
*/
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import { firstPort } from '@shared/inbounds.ts'
|
||||
import type { Inbound } from '@shared/inbounds.ts'
|
||||
import {
|
||||
autoGroupName,
|
||||
@@ -29,8 +30,10 @@ import { isChainedLine, kernel, linesFrom, membersOf, providers, runtime } from
|
||||
import { mergeMemberPreview } from '../member-preview'
|
||||
import type { MemberPreview } from '../member-preview'
|
||||
import OutboundCard from '../components/OutboundCard.vue'
|
||||
import ReachDialog from '../components/ReachDialog.vue'
|
||||
import SourcePicker from '../components/SourcePicker.vue'
|
||||
import IconEdit from '~icons/ri/edit-line'
|
||||
import IconReach from '~icons/ri/test-tube-line'
|
||||
import IconDelete from '~icons/ri/delete-bin-line'
|
||||
import IconUpgrade from '~icons/ri/arrow-up-circle-line'
|
||||
import IconRight from '~icons/ri/arrow-right-s-line'
|
||||
@@ -96,6 +99,24 @@ const subMatchAt = computed(() => firstMatchIndex(props.subRules))
|
||||
/** legacy 入站由配置顶层的端口字段声明,没有 proxy 字段可写,也不能删,只能升级。 */
|
||||
const locked = computed(() => props.inbound.isDefault)
|
||||
|
||||
/**
|
||||
* 可访问性测试走本机的哪个端口,测不了就是 null。
|
||||
*
|
||||
* 服务端拿这个端口当 HTTP 代理去访问目标,所以只有说 HTTP 的入站可以测;
|
||||
* 纯 socks 端口这条路走不通(同公网 IP 检测,server/host.ts)。
|
||||
*/
|
||||
const reachPort = computed(() =>
|
||||
props.inbound.type === 'http' || props.inbound.type === 'mixed'
|
||||
? firstPort(props.inbound.port)
|
||||
: null,
|
||||
)
|
||||
|
||||
/**
|
||||
* 对话框留在这里而不是像别的对话框那样提到 RouterPage:它不写配置文件也不改内核状态,
|
||||
* 不需要经过父组件那条 commit 链路,提上去只会多出一组只为传端口而存在的 props。
|
||||
*/
|
||||
const reachOpen = ref(false)
|
||||
|
||||
const activeTab = ref('')
|
||||
watch(
|
||||
() => props.panel.groups,
|
||||
@@ -460,6 +481,9 @@ const complete = computed(
|
||||
<span class="port mono">{{ inbound.port }}</span>
|
||||
<span class="name">{{ inbound.name }}</span>
|
||||
<div class="acts">
|
||||
<button v-if="reachPort !== null" type="button" @click="reachOpen = true">
|
||||
<IconReach /> 测试
|
||||
</button>
|
||||
<template v-if="!locked">
|
||||
<button type="button" @click="emit('edit')"><IconEdit /> 编辑</button>
|
||||
<button type="button" class="danger" @click="emit('remove')">
|
||||
@@ -802,6 +826,15 @@ const complete = computed(
|
||||
</template>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<!-- 放在 Transition 外面:切换入站时详情整块换掉,对话框不该跟着淡入淡出 -->
|
||||
<ReachDialog
|
||||
v-if="reachPort !== null"
|
||||
:open="reachOpen"
|
||||
:name="inbound.name"
|
||||
:port="reachPort"
|
||||
@close="reachOpen = false"
|
||||
/>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user