英文:
Make Requests to IP on Client's private network from the browser?
问题
以下是翻译好的部分:
"我正在尝试为飞利浦Hue API创建一个Web用户界面。这涉及通过用户的私人网络发送HTTP请求以与他们的Hue桥接设备通信。这是否可能?我目前正在尝试在页面加载时使用axios来执行,但似乎不在客户端执行。如果可能的话,这可能是一个巨大的安全漏洞,所以我认为不太可能。只是想知道是否有人有类似的经验。
我SvelteKit代码的示例:
export const load: PageLoad = (async () => {
try {
const headers = new AxiosHeaders();
headers.set('hue-application-key', BRIDGE_USERNAME);
const res = await axios.request({
url: `https://${BRIDGE_IP}/clip/v2/resource/light`,
headers: headers,
method: 'GET',
httpsAgent: new https.Agent({
checkServerIdentity: (hostname: string, cert: PeerCertificate) => {
// 确保对等证书的通用名称等于此请求所用的Hue桥标识。
if (cert.subject.CN === BRIDGE_SERVER_NAME) {
return undefined;
} else {
return new Error('服务器身份验证失败。CN与bridgeId不匹配。');
}
},
ca: BRIDGE_SSL_CERT,
}),
});
if (!res.data) {
throw error(500, '桥未返回数据');
}
return res.data
} catch (err) {
return { error: '加载灯失败' };
}
}) satisfies PageLoad;
我期望这在客户端上运行并从Hue桥接获取数据,但似乎只在服务器端工作。"
英文:
I'm trying to make a web UI for the Philips Hue API. This involves sending http requests over the users' private network to communicate with their hue bridge device. Is this possible? I'm currently trying to do it on a page load using axios, but it doesn't seem to execute on the client side. This would likely be a giant security vulnerability if possible, so I'm thinking it's not. Just wondering if anyone has experience trying to do something like this.
An example of my sveltekit code:
export const load: PageLoad = (async () => {
try {
const headers = new AxiosHeaders();
headers.set('hue-application-key', BRIDGE_USERNAME);
const res = await axios.request({
url: `https://${BRIDGE_IP}/clip/v2/resource/light`,
headers: headers,
method: 'GET',
httpsAgent: new https.Agent({
checkServerIdentity: (hostname: string, cert: PeerCertificate) => {
// Make sure the peer certificate's common name is equal to
// the Hue bridgeId that this request is for.
if (cert.subject.CN === BRIDGE_SERVER_NAME) {
return undefined;
} else {
return new Error('Server identity check failed. CN does not match bridgeId.');
}
},
ca: BRIDGE_SSL_CERT,
}),
});
if (!res.data) {
throw error(500, 'No data returned from bridge');
}
return res.data
} catch (err) {
return { error: 'Failed to load lights' };
}
}) satisfies PageLoad;
I expect this to run on the client and retrieve data from the hue bridge, but it only seems to work server-side.
答案1
得分: 1
By default, SvelteKit pages are rendered on the server (SSR) for the initial request and in the browser (CSR) for subsequent navigation. Take a look at the documentation here.
It is very likely that you are seeing the output of the server side only because you didn't navigate back and forth to this page after the initial render (refreshing the page is also considered an initial render).
If you want the +page.ts
to only run on the client, you can set the ssr
variable to false:
export const ssr = false;
This will force the page to render on the client only even for the initial request. At this point, you should see whether the request was successful or not in the browser itself.
Alternatively, if you still want some code to be run on the server for the initial render, you can move your request code to inside the onMount
method in the +page.svelte
file:
<script lang="ts">
import { onMount } from 'svelte';
onMount(async () => {
// Place your request here
});
</script>
英文:
By default, SvelteKit pages are rendered on the server (SSR) for the initial request and in the browser (CSR) for subsequent navigation. Take a look at the documentation here.
It is very likely that you are seeing the output of the server side only because you didn't navigate back and forth to this page after the initial render (refreshing the page is also considered an initial render).
If you want the +page.ts
to only run on the client, you can set the ssr
variable to false:
export const ssr = false;
This will force the page to render on the client only even for the initial request. At this point, you should see whether the request was successful or not in the browser itself.
Alternatively, if you still want some code to be run on the server for the initial render, you can move your request code to inside the onMount
method in the +page.svelte
file:
<script lang="ts">
import { onMount } from 'svelte';
onMount(async () => {
// Place your request here
});
</script>
答案2
得分: 0
以下是已翻译的内容:
当在用户的网络上向Hue Bridge发出客户端https请求时,由于未识别证书,请求失败。从Hue API文档中下载证书并在浏览器上安装后,我收到关于无法验证服务器名称的错误。
在服务器端进行请求时,我通过为自定义HTTP代理提供验证服务器名称的回调函数来解决了这个问题。由于这个选项在客户端的fetch或axios请求方法中不可用,我放弃了使用v2 API的想法,转而使用v1,它设置了允许CORS的标头。
以下是我最终得到的代码:
export const ssr = false;
export const load: PageLoad = (async () => {
try {
const opts = {
method: 'GET',
};
const res = await fetch(`http://${PUBLIC_BRIDGE_IP}/api/${PUBLIC_BRIDGE_USERNAME}/lights`, opts);
const data: HueLights = await res.json();
if (!data) {
throw error(500, '从桥返回的数据为空');
}
const lights = Object.keys(data).map((key): Light => {
const light: HueLight = data[key];
return {
id: key,
uniqueId: light?.uniqueid,
name: light?.name,
type: light?.config?.archetype,
color: {
xy: {
x: light?.state?.xy[0],
y: light?.state?.xy[1],
},
},
on: light?.state?.on,
dimming: {
brightness: light?.state?.bri,
minDimLevel: light?.capabilities?.control?.mindimlevel,
},
};
});
return { lights };
} catch (err) {
return { error: '加载灯失败' };
}
}) satisfies PageLoad;
请注意,已将代码部分保留原文不翻译。
英文:
When making a client-side https request to the Hue Bridge on the user's network, it failed because it didn't recognize the certificate. After downloading the certificate from the Hue API documentation and installing it on my browser, I got errors about not being able to verify the server name.
When making the request on the sever side, I was able to get around this by providing a callback function for verifying the server name in a custom http agent. Since this option isn't available on the client-side fetch or axios request methods, I abandoned the idea of using the v2 API and switched to using v1, which sets headers to allow for CORS.
Here is the code I ended up with:
export const ssr = false;
export const load: PageLoad = (async () => {
try {
const opts = {
method: 'GET',
};
const res = await fetch(`http://${PUBLIC_BRIDGE_IP}/api/${PUBLIC_BRIDGE_USERNAME}/lights`, opts);
const data: HueLights = await res.json();
if (!data) {
throw error(500, 'No data returned from bridge');
}
const lights = Object.keys(data).map((key): Light => {
const light: HueLight = data[key];
return {
id: key,
uniqueId: light?.uniqueid,
name: light?.name,
type: light?.config?.archetype,
color: {
xy: {
x: light?.state?.xy[0],
y: light?.state?.xy[1],
},
},
on: light?.state?.on,
dimming: {
brightness: light?.state?.bri,
minDimLevel: light?.capabilities?.control?.mindimlevel,
},
};
});
return { lights };
} catch (err) {
return { error: 'Failed to load lights' };
}
}) satisfies PageLoad;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论