使用html2Canvas将页面转化为canvas图片,最后长按保存到本地,史上最全 html2canvas 使用 踏坑之旅,没有之一

最近工作中遇到一个需求,类似这样
在这里插入图片描述
点击商品二维码,生成一张带有商品图片、标题、描述、二维码等信息的图片,用户长按进行保存。

在使用html2canvas进行项目开发的时候,遇到很多的问题,主要为一下方面:
1、图片跨域问题
2、截图不全问题
3、html2canvas在IOS13.4.1 上失效问题
4、canvas 嵌套 canvas 问题
5、img标签使用 base64 文件 在安卓真机上闪退问题

下面把我的探坑之旅和解决思路做个梳理 →

需求实现主要为以下三大步:

第一:如何生成二维码
第二:如何生成图片
第三:如何实现长按保存

  • 如何生成二维码
    这里我使用的是 qrcode 插件(官网地址:https://davidshimjs.github.io/qrcodejs/)

QRCode组件 附上代码:

import React, { PureComponent } from 'react'
import QRCode from 'qrcode'
import { color as d3Color } from 'd3-color'/*** 转化css颜色值为 RGBA hex形式的值 比如: #fff => #ffffffff* @param {css color} cssColor - css颜色值*/
const convertColor = (cssColor) => {const temp = d3Color(cssColor)if (temp === null) {return undefined}const alpha = Number(((temp.a || 1) * 255).toFixed(0))const result = [temp.r, temp.g, temp.b, alpha].map((e) => {const s = e.toString('16')return s.length < 2 ? `0${s}` : s}).join('')return result
}// 合并配置信息
const mergeConfig = (options) => {const {ecLevel,margin,width,color,background, // scale,} = optionsreturn {errorCorrectionLevel: ecLevel || 'M', // L, M, Q, H,margin: margin || 2,// scale: scale || 4,width: width || 100,color: {dark: convertColor(color) || '#000000ff',light: convertColor(background) || '#ffffffff',},}
}export default class ReactQRCode extends PureComponent {componentDidMount = () => {this.draw()}componentDidUpdate = () => {this.draw()}draw = () => {const { value, onDrowSuccess, ...rest } = this.propsconst cfg = mergeConfig(rest)QRCode.toCanvas(this.canvas, `${value}`, cfg).then(() => {onDrowSuccess && onDrowSuccess(this.canvas.toDataURL('image/jpeg'))}).catch((err) => {window.console.error(err)})}render() {return (<canvasstyle={{ width: 0 }}ref={(ref) => {this.canvas = ref}}/>)}
}

调用方式:

<QRCode value="http://abc" width={240} color="black" background="#fff" ecLevel="H" />
  • 如何生成图片
    经过多方考察调研,最终我使用的是 html2Canvas插件(官网地址:http://html2canvas.hertzen.com/)
    在这里插入图片描述
    在这里插入图片描述

html2Canvas的git⭐️⭐️指数还挺高的,并且浏览器兼容版本还不错。

下面开始进入正题→

  • 首先,想要使用html2Canvas画图之前,我们需要确保想要绘制的html页面已经生成,否则,画出来的图可能不完整,所以我们将画图的操作放到 componentDidMount 这一生命周期进行,确保页面已经渲染完成。
    附上代码:
class DrowProductQrCode extends Component {componentDidMount() {// 获取dom节点this.element = document.getElementById('productQrCode')this.canvas2Image()}canvas2Image = () => {html2canvas(this.element).then((canvas) => {const url = canvas.toDataURL('image/jpeg')const oImg = document.createElement('img')oImg.href = urldocument.body.appendChild(oImg)})}render() {const { qrCodeUrl, goodImg, name, title } = this.propsreturn (<div className={styles.container} id="productQrCode"><Flex><div className={styles.goodImg}><img className={styles.img} crossOrigin="Anonymous" src={goodImg} alt="商品图片" /></div><div className={styles.goodInfo}><div className={styles.title}>{name}</div><div className={styles.desc}>{title}</div></div></Flex><QrCode value={qrCodeUrl} width={220} /><div className={styles.tips}>扫描上面的二维码,查看内容</div></div>)}
}

这时候我们会发现控制台报错了
在这里插入图片描述
最直观的报错提示: been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.
意思是我们的 图片 跨域了,因为我们的图片大多都存储在阿里云或者其他服务器上,从我们本地去使用canvas去访问这张图片时,会存在跨域问题。

  • 接下来,如何解决跨域问题成了关键
    根据 html2Canvas 的官方文档我们可以知道:
    在这里插入图片描述
    html2Canvas为我们提供了两个参数以解决跨域问题,而这里,根据我们的报错信息(by CORS policy)我们使用的就是useCORS。
    于是,我们给代码加上这一参数
html2canvas(this.element, {useCORS: true,}).then((canvas) => {...})

结果还是不起作用,我们再一次在控制台看见了这可怕的鲜红字眼
在这里插入图片描述
这是怎么回事呐?
原来当我们在设置 useCORS: true 这一参数时,需要给img 标签加上 允许跨域的 标识(crossOrigin=“Anonymous”)

像这样

 <img className={styles.img} crossOrigin="Anonymous" src={goodImg} alt="商品图片" />

这时候我的内心已经小有雀跃了,持着激动的心,颤抖的手按下了保存按钮

啊哦。。。

在这里插入图片描述
这可怕的鲜红字眼又出现了。。
在这里插入图片描述
但其中有一条信息非常值得我们关注:No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

这表明,我们需要我们的后端在我们请求这张图片时给我么加上 Access-Control-Allow-Origin :允许跨域访问的域名 这项设置,必须这张图片是允许我们这个域 跨域访问时, 我们才能成功拿到这张图片。
有的人很好奇,为什么平时我们的代码中 ,使用过那么多img 标签,为什么没有遇到这个问题。这是因为 我们给 img 标签设置了 crossOrigin=“Anonymous” ,这才导致的。

接下来,我就屁颠屁颠去找到我司可爱的运维小哥,让他把我的域给允许跨域了。

现在!现在!我感觉已经越过了艰难险阻,是时候看见光明了,我再次怀着激动的心,颤抖的手刷新页面

我 我 我 我去!
这鲜红的字眼
在这里插入图片描述
让我有点恶心了

这 这 究竟是怎么肥事,我不忙明白了。运营小哥也仔仔细细的看了他加的配置, 写错了字母

于是我的眼里又燃起了希望呀,运营小哥一顿操作猛如虎,图片请求还是 500
在这里插入图片描述

这时候,我注意到了一个问题

为什么 5f68413ce4b0c9f1400679f6.jpg 这张图片被请求了好几次?而且居然前面还有请求成功的。这,这。。

在这里插入图片描述

这时候,百度的一篇文章给了我答案

CORS的配置方法一般是针对每个访问来源单独配置规则,勿将多个来源驾到一个规则,多个规则之间不要有覆盖冲突。

原来,因为我是在商品详情页引入的 DrowProductQrCode 组件,商品详情页可能有很多地方在同时访问这张商品的图片,这就导致了我们的配置冲突了,这张图片到底是走缓存还是走请求,走请求是一次还是多次?

所以我灵机一动,给我们的 卡片 DrowProductQrCode 里的这张图片加上一个时间戳,这样浏览器每次就会认为这是一个新的请求,这样就不在存在以上问题了。

const getTimestamp = new Date().getTime()
goodImg = `${goodImg}?timestamp=${getTimestamp}`

再次怀着激动的心,颤抖的手按下保存按钮, 终于成功的出来了商品图片
但是里面的二维码却没有出来。。。。
这这又是为什么呐
我们在仔仔细细的康康我们代码
在这里插入图片描述
我们在我们将要绘制canvas的html片段里又嵌套了一个canvas,这可如何是好,canvas画图的时候没有支持这个canvas嵌套canvas的操作。

  • 接下来如何解决canvas嵌套canvas的操作问题又成了关键

其实这很好解决
如果不能使canvas嵌套canvas,那我们就把里面的cavas转化成为html,不就行了,

// 在 QrCode 组件上传入一个回调函数,当二维码的 canvas 绘制完成之后,我们将canvas 转化成为 base 64 的文件返回回来

<QrCode onDrowSuccess={this.drowQrCodeSuccess} value={invitaionUrl(currentUserId, id)} width={220} />

在这里插入图片描述
我们的再去调一下后端上传图片的接口,将base 64 的图片上传上去,得到存在我们自己服务器上的二维码 url.

/*** 将以base64的图片url数据转换为Blob* @param base64    用url方式表示的base64图片数据* @return blob     返回blob对象*/
function dataURItoBlob(dataURI) {let byteStringif (dataURI.split(',')[0].indexOf('base64') >= 0) byteString = atob(dataURI.split(',')[1])else byteString = unescape(dataURI.split(',')[1])const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]const ia = new Uint8Array(byteString.length)for (let i = 0; i < byteString.length; i++) {ia[i] = byteString.charCodeAt(i)}return new Blob([ia], { type: mimeString })
}drowQrCodeSuccess = (url) => {uploadPublicFile(dataURItoBlob(url)).then((data) => {const imgUrl = getOssFileUrl(data)this.setState({qrCodeUrl: imgUrl,})}).catch(err => console.log('err', err))}

大家一定也想问,为什么不直接用base 64 的图片作为 img 标签的 url 放在 html 文件里,继续往后面读。。。

就这样,我们的 二维码 卡片 canvas终于画出来了,普天同庆,可喜可贺 吗?

我们突然发现画出来的canvas图不太完整,少了一些东西
在这里插入图片描述
头 头 头有点大…
在这里插入图片描述

  • 接下来如何解决截图不完整问题又成了关键

经过多方调研发现,是因为我们的内容过长,出现了滚动条或者其他原因导致 html2Canvas 截图不完整,网上有很多解决方法,但是经过我的多方实践,如果是出现了滚动条最好用的方法还是这个:
在这里插入图片描述
加上这两个参数就可以了,简单粗暴,效果完美

接下来,就是最后一步

  • 如何实现长按保存

二维码卡片画出来了,接下来就是保存图片。
老规矩,我们先将canvas 转化为 url

const url = canvas.toDataURL('image/jpeg')

然后写一个长按下载函数

componentDidMount() {// 监听容器点击事件this.longPress(this.downloadImg, this.element)}// 组件销毁时移除监听事件componentWillUnmount() {this.element.removeEventListener('touchstart', this.touchstart)this.element.removeEventListener('touchend', this.touchend)}// 封装一个长按方法longPress = () => {this.timeout = 0this.element.addEventListener('touchstart', this.touchstart, false)this.element.addEventListener('touchend', this.touchend, false)}touchstart = () => {// 长按时间超过800ms,则执行传入的方法this.timeout = setTimeout(this.downloadImg, 800)}touchend = () => {// 长按时间少于800ms,不会执行传入的方法clearTimeout(this.timeout)}// 图片下载downloadImg = () => {const { goodQrCode, fileName } = this.propsconst oImg = document.createElement('a')oImg.download = fileNameoImg.href = goodQrCodeoImg.click()oImg.remove()}

致此,下载就此完成。在pc端操作起来特别顺畅

于是,我拿出测试机,在ios手机上测试, IOS手机长按会自动调起系统的保存图片方法,好像没什么问题,虽然没使用我们的代码,但是目的是达到了。接下来就是安卓机,

长按,闪退。。。
长按, 闪退。。。
换个安卓机
长按,闪退。。。
长按, 闪退。。。
在这里插入图片描述

怎么肥事。。

拿出数据线,打开uc-devtools, 连接手机,真机调试一看,发现每次长按后,页面就被 crash 掉了。经过百度发现,因为 base 64的文件太长了,在很多手机上无法支持预览及下载。

这下明白了为什么我上面生成的 qrCode 为什么不直接使用 base 64的文件作为 img 的 src 路径了吧。

老办法,我们调用后端接口,将图片上传到我们自己的服务器,然后用后端返回的地址作为图片链接。

你以为这就结束了吗?
no no no
坑还没踏完呐

测试在测试的时候,发现ios的一款手机的二维码怎么也出不来

在这里插入图片描述

经过调查发现,我所使用的 html2canvas 版本(1.0.0-rc.7 ) 在IOS13.4.1 系统版本不生效,需要把它降到 html2canvas 1.0.0-rc.4 版本方可成功
附上代码 ->

//  npm 管理
//  先卸载旧版本
npm uninstall html2canvas
//  安装新版本
npm install --save html2canvas@1.0.0-rc.4//  yarn 管理
//  先卸载旧版本
yarn remove html2canvas
//  安装新版本
yarn add html2canvas@1.0.0-rc.4

完美解决!

但是大家也知道,使用 a 标签下载图片 基本不太现实,他只能新开一个窗口,预览图片,然后用户自己手动截屏或者靠系统、浏览器自带的长按保存图片方法。想要是实现长按保存的效果只能靠调起 native 方法、或者后端实现下载功能,我们请求接口来得以实现。

那么问题来,如果后端和native都不愿意或者没法实现,产品又非让你做出这个效果来
那你就… 你就… 你就… 找他理论(低头)去

最后附上完整代码逻辑:
GoodsDetailPage:

handleCanvas2ImageOK = (url) => {this.setState({goodQrCode: url,productQrCodeDivShow: false,})}render() {return {<div>// 商品二维码卡片<GoodQrCodeModal// 	影藏modal弹框方法hideCodeModal={this.hideCodeModal}// 是否展示modal弹框codeModalShow={codeModalShow}// qrcode 生成的二维码上传到后端后的url地址goodQrCode={goodQrCode}// 下载的文件名fileName={name}/>// 生成商品二维码的HTML代码, 通过 productQrCodeDivShow 字段控制其展示// productQrCodeDivShow 的作用就是让GoodsDetailPage页面渲染时将 商品二维码卡片 生成,然后返回 商品二维码卡片 的url, 影藏商品二维码的HTML。{productQrCodeDivShow && (<ProductQrCodecurrentUserId={userId}detail={detail}onCanvas2ImageOK={this.handleCanvas2ImageOK}/>)}</div>}
}

ProductQrCode:

/*** 将以base64的图片url数据转换为Blob* @param base64    用url方式表示的base64图片数据* @return blob     返回blob对象*/
function dataURItoBlob(dataURI) {let byteStringif (dataURI.split(',')[0].indexOf('base64') >= 0) byteString = atob(dataURI.split(',')[1])else byteString = unescape(dataURI.split(',')[1])const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]const ia = new Uint8Array(byteString.length)for (let i = 0; i < byteString.length; i++) {ia[i] = byteString.charCodeAt(i)}return new Blob([ia], { type: mimeString })
}class ProductQrCode extends Component {state = {qrCodeUrl: '',}componentDidMount() {}drowQrCodeSuccess = (url) => {uploadPublicFile(dataURItoBlob(url)).then((data) => {const imgUrl = getOssFileUrl(data)this.setState({qrCodeUrl: imgUrl,})}).catch(err => console.log('err', err))}render() {const { currentUserId, detail, onCanvas2ImageOK } = this.propsconst { name, title, pics, id } = detail || []const getTimestamp = new Date().getTime()let goodImg = getObjField(getOssFileUrl(pics), '[0]')goodImg = `${goodImg}?timestamp=${getTimestamp}`const { qrCodeUrl } = this.statereturn (<div><QrCode onDrowSuccess={this.drowQrCodeSuccess} value={invitaionUrl(currentUserId, id)} width={220} />// 确保qrcode 已生成 二维码,并且上传到服务器获取到url地址{qrCodeUrl && (<DrowProductQrCodeonCanvas2ImageOK={onCanvas2ImageOK}qrCodeUrl={qrCodeUrl}name={name}title={title}goodImg={goodImg}/>)}</div>)}
}export default ProductQrCodeclass DrowProductQrCode extends Component {componentDidMount() {// 获取dom节点this.element = document.getElementById('productQrCode')this.canvas2Image()}canvas2Image = () => {const { onCanvas2ImageOK } = this.propshtml2canvas(this.element, {// 允许跨域 (allowTaint, useCORS)设置其一useCORS: true,scrolly: 0,scrollx: 0,}).then((canvas) => {const url = canvas.toDataURL('image/jpeg')// 将canvas生成的 base64 的地址转化为 blob(base64 过长导致手机下载出现问题) , 上传到oss获取图片URLconst blobFile = dataURItoBlob(url)uploadPublicFile(blobFile).then((data) => {const imgUrl = getOssFileUrl(data)onCanvas2ImageOK && onCanvas2ImageOK(imgUrl)}).catch(err => console.log('err', err))})}render() {const { qrCodeUrl, goodImg, name, title } = this.propsreturn (<div className={styles.container} id="productQrCode"><Flex><div className={styles.goodImg}><img className={styles.img} crossOrigin="Anonymous" src={goodImg} alt="商品图片" /></div><div className={styles.goodInfo}><div className={styles.title}>{name}</div><div className={styles.desc}>{title}</div></div></Flex><img className={styles.qrCode} crossOrigin="Anonymous" src={qrCodeUrl} alt="商品图片" /><div className={styles.tips}>扫描上面的二维码,查看内容</div></div>)}
}

GoodQrCodeModal:

import React from 'react'
import { Modal } from 'antd-mobile'
import styles from './GoodQrCodeModal.scss'class GoodQrCodeModal extends React.PureComponent {componentDidMount() {}render() {const {codeModalShow, hideCodeModal, goodQrCode, fileName,} = this.propsreturn (<ModalclassName={styles.codeModal}visible={codeModalShow}maskClosabletransparentonClose={hideCodeModal}><GoodQrCodeImg goodQrCode={goodQrCode} fileName={fileName} /></Modal>)}
}export default GoodQrCodeModalclass GoodQrCodeImg extends React.PureComponent {componentDidMount() {this.element = document.getElementById('goodQrCode')// 监听容器点击事件this.longPress(this.downloadImg, this.element)}componentWillUnmount() {this.element.removeEventListener('touchstart', this.touchstart)this.element.removeEventListener('touchend', this.touchend)}// 封装一个长按方法longPress = () => {this.timeout = 0this.element.addEventListener('touchstart', this.touchstart, false)this.element.addEventListener('touchend', this.touchend, false)}touchstart = () => {// 长按时间超过800ms,则执行传入的方法this.timeout = setTimeout(this.downloadImg, 800)}touchend = () => {// 长按时间少于800ms,不会执行传入的方法clearTimeout(this.timeout)}// 图片下载downloadImg = () => {const { goodQrCode, fileName } = this.propsconst oImg = document.createElement('a')oImg.download = fileNameoImg.href = goodQrCodeoImg.click()oImg.remove()}render() {const { goodQrCode } = this.propsreturn (<img id="goodQrCode" className={styles.goodQrCode} src={goodQrCode} alt="商品二维码" />)}
}

以上就是全部大致思路啦
如有bug, 请多指教✍️✍️✍️

如果对你有帮助,就给我点个赞吧

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/515495.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

饿了么4年+阿里2年:研发路上的一些总结与思考

我是在2014年入职饿了么&#xff0c;从前端和PHP一直做到后端架构和团队&#xff0c;从2014年到2017年陆续负责过公司客服、销售、代理商、支付、清结算、订单这些业务的产研与团队&#xff1b;2018年从业务研发团队抽身&#xff0c;6个人组起一个小组投身机器学习&#xff0c;…

到底谁在使用低代码?钉钉低代码用户画像:非IT人员占8成

编辑 | 宋慧 供稿 | 钉钉 头图 | 付费下载于视觉中国 低代码开发需求到底有多大&#xff1f;谁在使用低代码开发&#xff1f;3月2日&#xff0c;钉钉发布低代码开发者画像&#xff1a;一二线城市的80、90后是低代码开发的主力军&#xff0c;但20岁以下和50岁以上开发者也占比近…

都已经十岁的ApacheDubbo,还能再乘风破浪吗?

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; 纵观中国开源历史&#xff0c;你真的没法找到第二个像 Dubbo 一样自带争议和讨论热度的开源项目。 一方面&#xff0c;2011 …

前后端分离,如何解决跨域(代理模式)、路由拦截(进入页面需要登录)以及请求拦截(登录TOKEN失效)等问题(初学者)

前端时间项目需要发布一个较大的版本&#xff0c;工作比较忙&#xff0c;加了好多个晚上的班&#xff0c;感觉自己有点缺氧了。最近稍微闲下来了&#xff0c;顺便调休了三天&#xff0c;刚刚给家里来了个大扫除&#xff0c;看着这干干净净的小家&#xff0c;心里顿时舒服了很多…

秒懂云通信:通信圈黑话大盘点

原文链接 本文为云栖社区原创内容&#xff0c;未经允许不得转载。

从开源视角分析,搞定边缘计算云原生方案选型

作者 | lanliang来源 | 边缘计算社区头图 | 下载于视觉中国随着Kubernetes已经成为容器编排和调度的事实标准&#xff0c;各大公有云厂商都已经基于Kubernetes提供了完善的Kubernetes云上托管服务。同时也看到越来越多的企业、行业开始在生产中使用Kubernetes, 拥抱云原生。在各…

不太平凡的2020、平凡的我

这是去年12月31号的年终总结立下的flag。 古人常说&#xff1a;千里马常有&#xff0c;而伯乐不常有。 如今都是&#xff1a;flag常有&#xff0c;而实现不常有。2020年6月&#xff0c;在疫情的笼罩着&#xff0c;我们这一届 应届生 在无声无息中就成为了 毕业生。因为2019年7…

银行业数据治理之数据资产管理

前言&#xff1a; -更多关于数智化转型、数据中台内容请加入阿里云数据中台交流群—数智俱乐部 &#xff08;文末扫描二维码或点此加入&#xff09; -阿里云数据中台官网 https://dp.alibaba.com/index 随着2018年银保监发文《银行业金融机构数据治理指引》&#xff0c;各银监局…

架构简洁之道:从阿里开源应用架构COLA说起

导读&#xff1a;COLA 的主要目的是为应用架构提供一套简单的可以复制、可以理解、可以落地、可以控制复杂性的”指导和约束"。在实践中作者发现 COLA 在简洁性上仍有不足&#xff0c;因此给 COLA 做了一次“升级”&#xff0c;在这次升级中&#xff0c;没有增加任何新的功…

html、css、js、react、vue 文字一行一行显示出来

前端时间在做 年报&#xff0c;就不难涉及到 年报 具有的几大特性&#xff1a; 1、页面滑动特效 2、文字一行一行出现特效 3、页面内动画 等等 这片文章主要展示一下 文字一行一行出现特效 代码&#xff08;react 为例&#xff09; 先看效果图&#xff1a; 第一步&#xff…

哪家互联网公司涨薪最厉害?居然不是阿里腾讯

最近脉脉职言区有一条讨论火了&#xff1a;哪家互联网公司涨薪最厉害&#xff1f;按照拼多多员工的说法&#xff0c;应届毕业生可以拿比腾讯阿里高30%的薪资&#xff0c;而有工作经验的员工普遍薪资水平也高出业内30%~50%以上。而且在去年由于疫情众多企业降薪、甚至裁员的状况…

MongoDB 安装与配置~linux

文章目录一、 安装建议二、 安装步骤2.1. 下载2.2. 解压缩2.3. 重命名2.4. 配置环境变量2.5. 使其生效2.6. 配置MongoDB2.7. 启动MongoDB2.8. 网络安全组一、 安装建议 MongoDB 可以在mac/win/linux上安装&#xff0c;我个人建议在linux上安装会更好&#xff0c;这样测试起来更…

节省服务器成本50%以上!独角兽完美日记电商系统容器化改造实践

完美日记创立于2017年&#xff0c;这家公司上线不到两年即成为天猫彩妆销冠&#xff0c;2019年成为11年来第一个登上天猫双十一彩妆榜首的国货品牌&#xff0c;包揽天猫2019全年彩妆销冠&#xff1b;2020年4月成为首个亮相天猫超级品牌日的国货彩妆品牌&#xff0c;同时勇破彩妆…

浏览器从输入URL到页面渲染过程 —— 浏览器的进程与线程

之前我有总结过一篇经典面试题&#xff1a;浏览器从输入URL到页面渲染过程&#xff0c;接下里我将对某些知识点进行更细致的解析。 浏览器从输入URL到页面渲染过程 系列文章&#xff1a; &#xff08;二&#xff09;&#xff1a;浏览器从输入URL到页面渲染过程 ——页面渲染流…

MongoDB 的可视化管理工具~连接腾讯云MongoDB服务

不论是mysql或者redis或者es&#xff0c;我们都会使用远程的客户端工具来连接数据库server&#xff0c;那么目前的linux上锁安装的MongoDB就是server端&#xff0c;我们需要有一个客户端来进行可视化的管理&#xff0c;常用的可以使用Navcat来操作&#xff0c;当然使用其他的GU…

云原生时代业务架构的变革:从单体迈向Serverless

如今&#xff0c;各行各业都在谈数字化转型&#xff0c;尤其是新零售、传媒、交通等行业。数字化的商业形态已经成为主流&#xff0c;逐渐替代了传统的商业形态。在另外一些行业里&#xff08;如工业制造&#xff09;&#xff0c;虽然企业的商业形态并非以数字化的形式表现&…

冯诺依曼架构的 IO 鸿沟,谁能来填补?

作者 | 宋慧头图 | 下载于视觉中国随着AI技术、数据分析等领域兴起&#xff0c;数据变得越来越重要了&#xff0c;数据处理往往需要用到大量的内存&#xff0c;数据量爆发式增长让各种内存密集型应用层出不穷&#xff0c;如Redis数据库、SAP HANA企业核心系统。在CSDN 2019、20…

使用Git后10件你可能需要“反悔”的事

云栖号资讯&#xff1a;【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯&#xff0c;还在等什么&#xff0c;快来&#xff01; Git是目前世界上最优秀最流行的分布式版本控制系统&#xff0c;也是程序员们日常使用最频繁的工具之一&#xff08;几乎每天都…

SpringBoot 整合MongoDB

文章目录1. 引入依赖2. 在yml中添加配置3. 在启动类中开启mongodb在model中添加依赖&#xff0c;为什么在model中添加&#xff1f;因为会有映射的实体类MongoObject对应mongodb中的数据表对象&#xff1a;1. 引入依赖 <dependency><groupId>org.springframework.b…

浏览器从输入URL到页面渲染过程 ——页面渲染流程

之前我有总结过一篇经典面试题&#xff1a;浏览器从输入URL到页面渲染过程 &#xff0c;接下里我将对某些知识点进行更细致的解析。 浏览器从输入URL到页面渲染过程 系列文章&#xff1a; &#xff08;一&#xff09;&#xff1a;浏览器从输入URL到页面渲染过程 —— 浏览器的…