当前位置: 首页 > news >正文

如何做网站对话框淘金网站建设

如何做网站对话框,淘金网站建设,网站标题tdk,seo排名优化培训前言 前段时间有个需求#xff0c; 就是我们有做一个 web 的投屏端#xff0c; 可以将另一个客户端(比如 android#xff0c;ios#xff0c;win#xff0c;mac) 投屏到 web 站点来。 但是期间因为涉及到引流#xff0c; 所以针对投屏的客户端是否在同一个局域网下要做不同…前言 前段时间有个需求 就是我们有做一个 web 的投屏端 可以将另一个客户端(比如 androidioswinmac) 投屏到 web 站点来。 但是期间因为涉及到引流 所以针对投屏的客户端是否在同一个局域网下要做不同的判断如果在同一个局域网下那么就可以免费使用如果不是的话就会有其他的引导。 所以我们得到客户端的 ip 地址之后需要判断当前浏览器是否跟这一台客户端在同一个局域网下。 有几种判断方式 以下的测试数据都是基于 chrome 98 的浏览器 早期的浏览器可能会有不同的表现 让客户端开启一个本地端口然后浏览器去请求这个端口 最简单的方式就是让这个客户端开启一个本地端口就是类似于 ipport 的方式可以是 http 也可以是 websocket 的方式。 然后让浏览器去请求这个端口。 如果可以请求成功那么就说明是在同一个局域网。 不过这边有几个问题: 1.1. 在 https 下会有问题 如果当前的站点是 https 的话那么在 https 下请求 http 协议的 ip 形式的接口的话 浏览器是会直接 block 掉的 (请求不会到服务端这边) 1 如果是 ws 协议的 ip 地址的 websocket 的话也是一样会被 block 掉 (请求不会到服务端这边) 1 那如果是 https 或者是 wss 下的 ip 形式的接口呢 (客户端是没有合格的证书的就算加上 tls 也是用自制证书的 ip 地址的方式)是不是就可以? 答案肯定是不行的 直接就报证书错误了 (除非事先这个接口已经在浏览器那边事先手动允许访问了) 1 所以总结一下 在 https 的站点下 非 tls 的 http 和 ws 的 ip 地址的接口请求会直接 block 掉 在 https 的站点下 tls 的 https 和 wss 的 ip 地址的接口请求会报证书错误也是 block 1.2. https 请求 localhost 的例外情况 那有没有例外呢在我的测试中还真有一个例外 就是如果是本机的客户端的服务以 localhost 的 host 方式不管是 http://localhost:3000 还是 ws://localhost:3000, 都可以在 https 的站点下 work 不过两者有差别: 如果是 localhost 的 http 请求的话浏览器也会 block (测试的时候之所以 block 是因为 CORS 限制)不过他只会 block 返回值但是请求是有出去的也就是说返回值是 200只不过 js 没法取的返回值但是服务端是有收到这个请求的 1 如果是 localhost 的 ws 请求的话 哪怕是在 https 的站点也是可以 work 的。就跟在 http 站点中表现一样 关于这一点其实我也有点疑惑正常来说 localhost 的形式跟 ip 地址的形式应该差别不大才对 但是实验的结果却是 ip 地址的不行localhost 就可以 差别可能就是 ip 地址的不仅仅是本机同一个局域网下的机器都有但是 localhost 却是限于本机上开启的服务 可能相对来说也会比较安全吧。 事实上我们还真有一个服务是在 https 站点下调用 localhost 服务接口的就是我们 win 端应用在进行第三方 google 登录授权的时候就是跳转到我们的 https 下的官网站点的 web 页面进行授权的 然后授权完成之后就会调用该应用创建的 localhost 的服务接口将信息传递到 win 端的应用 从而完成整个第三方授权过程。 1.3. 在 http 下也会有问题 在 https 下有问题 其实在 http 下也会有问题的 chrome 可能在 2022-05-17 之后 http 协议的远程站点就不能再请求本地的专用网络了。包括 ip 形式的 localhost 形式的。 之前我还针对过这个情况进行过一次兼容: chrome 94 之后 http 远程站点请求 ip 地址报 CORS 错误 综上所述 通过请求 ipport 的方式请求客户端暴露的接口来判断跟客户端是处于同一个局域网的策略是行不通的 根据 ip 网段来判断是否是同一个局域网 还是一种方式就是既然可以得到 客户端的 ip (可以通过很多途径比如去服务端取或者直接两者连接同一个 websocket 通道然后进行信息转发之类的) 那能不能直接通过这个 ip 是不是局域网 ip 网段来直接确定是不是在同一个局域网。 我们知道从 0.0.0.0 到 255.255.255.255 这些网段中其中有一些网段是给局域网的包括: a类网 10.0.0.0~10.255.255.255 b类网 172.16.0.0~172.31.255.255 c类网 192.168.0.0~192.168.255.255 那能不能直接根据客户端传过来的 ip 地址来判断是不是在同一个局域网内比如这样子判断: checkIpInLAN: function (ip) { return ip (ip.indexOf(“10.”) 0 || ip.indexOf(“172.”) 0 || ip.indexOf(“192.168”) 0); }, 其实也是不准确的因为这边混淆了一个概念以上确实是属于局域网的网段 但是该网段不一定跟当前的浏览器在同一个局域网。 因为同样是局域网的网段但是相互之间可能就是不通的比如我们公司提供给客人的wifi和我们内部人员自己使用的 wifi就是都属于 192.168.x.x 的局域网网段 但是两者其实是不通 也就是两者不在同一个局域网下。 所以这种方式也是没办法判断浏览器和客户端是在同一个局域网下的 通过 webrtc 的 stun/turn 得到局域网 ip然后扔给客户端让客户端去 ping 还有一种方式就是通过 webrtc 的 stun/turn server 去获取当前浏览器的局域网 ip然后将这个 ip 扔给客户端让客户端去 ping如果通说明就在同一个局域网。 但是我后面试了一下发现这种方式会有问题 他返回的 host 信息是有问题的变成这样子: {“candidate”:“candidate:1316551156 1 udp 2113937151 493c5821-465b-41d5-9cfe-f0b703d3add6.local 57516 typ host generation 0 ufrag gjxD network-cost 999”,“sdpMid”:“0”,“sdpMLineIndex”:0} 局域网 ip 就变成这样子 493c5821-465b-41d5-9cfe-f0b703d3add6.local 后面查了一下原来 chrome 在 75 版本之后使用了一种 mDNS 的技术将 local ip 匿名了: Google Chrome - Anonymize local IPs exposed by WebRTC prevents live view in cloud console 导致我们没办法看到这个局域网 ip。 这边附上操作代码: const findIP (onNewIP) { const myPeerConnection window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection const pc new myPeerConnection({ iceServers: [ {urls: ‘stun:stun.l.google.com:19302’}, {urls: ‘stun:stun.services.mozilla.com:3478’}, {urls: ‘stun:stun.qq.com:3478’} ] }) const noop () {} const localIPs {} const ipRegex /([0-9]{1,3}(.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g const ipIterate (ip) { if (!localIPs[ip]) onNewIP(ip) localIPs[ip] true } pc.createDataChannel(‘’) // create a bogus data channel pc.createOffer(sdp { sdp.sdp.split(‘\n’).forEach(line { if (line.indexOf(‘candidate’) 0) return line.match(ipRegex).forEach(ipIterate) }) pc.setLocalDescription(sdp, noop, noop) }, noop) // create offer and set local description pc.onicecandidate (ice) { // listen for candidate events if ( !ice || !ice.candidate || !ice.candidate.candidate || !ice.candidate.candidate.match(ipRegex) ) return ice.candidate.candidate.match(ipRegex).forEach(ipIterate) } } const addIP (ip) { document.body.append(----get ip: ${ip}) } findIP(addIP) 这种方式虽然没办法得到局域网 ip 但是却可以得到外网 ip 以下就是我利用上述的程序得到的 外网 ip 125.xx.xx.250 : {“candidate”:“candidate:842163049 1 udp 1677729535 125.xx.xx.250 55956 typ srflx raddr 0.0.0.0 rport 0 generation 0 ufrag 12LL network-cost 999”,“sdpMid”:“0”,“sdpMLineIndex”:0} 这个在 chrome 是有配置项的: chrome://flags/#enable-webrtc-hide-local-ips-with-mdns, 默认是开启的。 如果将其设置为 disable 后 那么是不会启用 mDNS 技术来隐藏真实的 local ip 那么直接就是局域网 ip 了 1 {“candidate”:“candidate:1316551156 1 udp 2122260223 192.168.40.51 56234 typ host generation 0 ufrag n4Ma network-id 1”,“sdpMid”:“0”,“sdpMLineIndex”:0} 有一种例外情况可以忽略 mDNS 查阅了相关资料发现有一种例外情况也可以显示原始的局域网 ip: 对应用程序的影响 当该功能处于活动状态时ICE 候选主机中的私有 IP 地址将被替换为 mDNS 主机名例如1f4712db-ea17-4bcf-a596-105139dfd8bf.local 。 目前除具有 getUserMedia 权限的站点外该功能对所有站点都有效假定这些站点具有较高的用户信任度。 WebRTC 公开的私有 IP 地址更改为 mDNS 主机名groups.google.com/g/discuss-webrtc/c/6stQXi72BEU 那就是在有启用 getUserMedia 权限的站点 (要是 https 的站点) 所以将上述的代码最后一行改为: navigator.mediaDevices.getUserMedia({ video: false, audio: true }).then( stream { findIP(addIP) }).catch(err { findIP(addIP) }) 这时候就会弹出授权框 1 点击允许之后就会出现局域网 ip 了 (而且下一次不需要再授权了只要有权限那么就会有不匿名的局域网 ip) 1 跟客户端建立起 webrtc 连接如果是在一个局域网的话会有 localCandidate 信息 目前最稳妥的方式就是跟客户端建立起 webrtc 连接 这时候如果真的是在同一个局域网下的话就可以得到 localCandidate同时他的值是 host 的话 那么就可以认为是在同一个局域网下了。 具体操作就是在 ice 连接成功的情况下 这时候我们可以获取 webrtc 的统计数据(这个是一个异步) 通过 RTCPeerConnection 对象的 getStats 方法: const report await this.#pc.getStats() // 遍历report按照 type 来分类 /** type {Recordstring, any[]} */ const data {}; report.forEach((item) { if (data[item.type]) { data[item.type].unshift(item) } else { data[item.type] [item] } }); return data 然后这时候得到统计数据之后, 就可以去找到当前连接的通道 transport, 然后在 candidate-pair 找到这个通道, 然后接下来在 local-candidate 找到这个 id, 最后一步就是判断是不是 host 了 具体的代码如下: /** 通过 webrtc 的 stat 数据来判断当前连接的通道是否是局域网param statreturns {boolean} */ checkIsLocalCandidateType(stat){ const originRaw stat._raw const throwErr (msg) { throw { msg: [checkIsLocalCandidateType]: ${msg} } } const findLocalCandidate (targetCandidate) { if(targetCandidate.length){ let localCandidateId targetCandidate[0][“localCandidateId”] // 然后接下来在 local-candidate 找到这个 id if(originRaw[“local-candidate”]){ let targetLocalCandidate originRaw[“local-candidate”].filter(item item.id localCandidateId) if(targetLocalCandidate.length){ let candidateType targetLocalCandidate[0][“candidateType”] // 最后一步就是判断是不是 host 了 logger.debug([WebRtcProcess] checkIsLocalCandidateIdFromWebRtcStats: ${candidateType}) return candidateType “host” }else{ throwErr(“local-candidateType not found”) } }else{ throwErr(“local-candidate not found”) } }else{ throwErr(“targetCandidate not found”) } } // 找到当前连接的通道, 这个是 chrome 的流程 if(originRaw.transport?.length){ const selectedCandidatePairId originRaw.transport[0].selectedCandidatePairId // 然后在 candidate-pair 找到这个通道 if(originRaw[“candidate-pair”]?.length){ let targetCandidate originRaw[“candidate-pair”].filter(item item.id selectedCandidatePairId) return findLocalCandidate(targetCandidate) }else{ throwErr(“candidate-pair not found”) } }else{ // firefox 是没有 transport 参数的要额外处理 if(originRaw[“candidate-pair”]?.length){ let targetCandidate originRaw[“candidate-pair”].filter(item item[“selected”] true item[“state”] “succeeded”) return findLocalCandidate(targetCandidate) } // 有些旧的浏览器比如 safari 11.1.2就会出现找不到 local-candidate 参数的情况 } return false } 这个是在 ice 连接之后 第一次获取 getStats 方法的时候就可以判断 因为 ice 连接之后说明当前的 webrtc 肯定是有连接的 transport 通道的 只要当前的这一条通道的 local-candidate 的值是 host 那么就肯定是在同一个局域网下。 通过这种方式绝大部分情况下是可以判断浏览器和客户端是在同一个局域网下但是有一种情况下会误判 就是当前是局域网但是网络连通不好导致不是 host 先连上而是穿透(srflx)或者转发(relay)先连上 transport, 这时候第一次的 getStats 就不会是 host 了因为他当前的连接通道确实不是 host。 同时需要注意一点的是正常情况下这个 host 的 RTCIceCandidate 也是不会显示 局域网 ip 的 而且他不是用 mDNS 加密而是直接为空: { “id”: “RTCIceCandidate_1wdP0rnA”, “timestamp”: 1651027428646, “type”: “local-candidate”, “transportId”: “RTCTransport_audio_1”, “isRemote”: false, “networkType”: “unknown”, “ip”: “”, “address”: “”, “port”: 63261, “protocol”: “udp”, “candidateType”: “host”, “priority”: 2113937151 } 也是只有在启用 getUserMedia 权限才会显示局域网 ip 出来。 一样建立 webrtc 连接但是双方只接受 host ice 如果还能连上那么肯定是在同一个局域网 上述的情况是连接上 webrtc 之后才去判断是不是走 host 的 transport 通道再去判断当前是否是局域网连接。 但是如果我们在传输交换 ice 的时候只传和接收 局域网 ice 的话 那么能连接上 webrtc 的情况下肯定是局域网。 因为在只有 host 模式下 ice 可以连接上说明两端肯定是在同一个局域网下 所以就要改成双方在发送 ice 的时候只发送 host 模式下的 ice, 类似于这样子 {“sdpMLineIndex”:0,“sdpMid”:“0”,“candidate”:“candidate:559267639 1 udp 2122202367 ::1 45061 typ host generation 0 ufrag yvH5 network-id 2”} {“sdpMLineIndex”:0,“sdpMid”:“0”,“candidate”:“candidate:2065939615 1 udp 2122260223 192.168.197.13 47089 typ host generation 0 ufrag yvH5 network-id 3 network-cost 10”} 然后在 this.#pc.addIceCandidate(new RTCIceCandidate(item), () { 添加的时候就会只有 host 的 ice 了。 这种情况下对于一端浏览器端一端其他端(windowsandroid ios)这个其他端因为有更详细的底层 sdk 的 api 所以可以做到只发送 host 的 ice。 但是对于两端都是浏览器端的情况因为预置的 RTCIceTransportPolicy 只有两个值 relay 和 all 并没有类似于 only-local 的值没办法控制只发送 host ice 的情况 enum RTCIceTransportPolicy { “relay”, “all” }; mozillaw3c.github.io/webrtc-pc/#rtcicetransportpolicy-enum 但是我们可以在接收添加 ice 的时候过滤掉非 host 的 ice比如这样子: /** 添加ICEpc.addIceCandidate */ addIce (data) { return new Promise((resolve) { const RTCIceCandidate window.RTCIceCandidate || (window as any).mozRTCIceCandidate || (window as any).webkitRTCIceCandidate data.forEach(item { // 只接收 host 的 ice if(JSON.stringify(item).includes(“typ host”)){ this.#pc.addIceCandidate(new RTCIceCandidate(item), () { logger.debug([PeerConnection]: add ice success: ${JSON.stringify(item)}) this.#emitter.emit(‘addIceStatus’, ‘success’) }, (err) { logger.error([PeerConnection]: add ice fail: ${err}) this.#emitter.emit(‘addIceStatus’, ‘fail’) }) } }) resolve(data) }); } 这样子如果 ice 可以连接上那么肯定两端是在同一个局域网中。 虽然通过这种方式可以 100% 判断是否在同一个局域网中 但是会伴随两个小问题: 因为只接收 host ice所以连接失败的情况下没办法判断是 webrtc 整体连接不上 还是因为只有 host ice 连接不上这个不好定位(因为有可能不卡 host ice 的话是可以连接上的) 判断时间会比较长因为要等到 host ice 连接不上至少也要给予 5s 的尝试连接时间或者更久才能准确得到信息 太短的时候会不准确因为有些虽然在同一个局域网但是网络不太行需要更长的时间来连接 总结 本文介绍了几种浏览器判断跟客户端是否在同一个局域网的方式 前三种都有一定的问题 第四种一定情况下在网络比较差的情况下会有误判。 只有第五种是可以 100% 判断是在同一个局域网下的情况。 https://kebingzao.com/2022/03/29/browser-detect-lan/
http://www.sadfv.cn/news/340646/

相关文章:

  • 网站制度建设情况sns有哪些著名的网站有哪些
  • 做培训的网站个人做网站 用什么语言
  • 郑州网站建设服务商门业网站模板下载
  • 自己如何做网站关键词排名网站建设的重要性意义
  • 营销型网站建设论坛wordpress上传网页
  • 秦皇岛网站建设哪家好电子商务是干什么的工资一般多少
  • 重庆seo网站网站构成要素
  • 重庆公司专业建站收录查询站长工具
  • 服务类网站模板成都房建设部网站
  • 太原搭建网站的公司哪家好崇明建设镇虹桥村网站
  • 用来做网站的软件潍坊网站建设熊掌号
  • wordpress建站上传不了图片wordpress如何设置邮箱验证码
  • 做网站对企业有什么好处公司网站后台更新
  • 做牛排的网站wap手机
  • 自己做网站卖二手车如何做地方门户网站
  • 连云港网站备案在哪wordpress 4.9.7 中文
  • 深圳企业网站建设开发费用hao123上网从这里开始
  • 怎么看到网站开发时间莱山做网站的公司
  • 有没有专门做平铺素材的网站wix怎样做网站
  • 虚拟网站源码电商网站建设需要哪些技术
  • wordpress多站点cdnwordpress链接速度慢
  • 在建设局网站备案怎么弄优化网站搭建
  • wordpress建站 网盘视频教程wordpress 添加版权
  • 怎么在百度上能搜到自己的网站wordpress前端用户
  • 百度有做企业网站吗作风建设年活动网站
  • 河北省建设银行网站首页购买域名后怎么建网站
  • php asp jsp 网站转发文章赚钱的网站建设
  • 自己建设个小网站要什么关于网站集约化建设的讲话
  • 专门做衣服特卖的网站wordpress 媒体库缩略图生成
  • 网站开发方式网站改版方案怎么写