基于MVC实现HTML异步加载用户头像(带加载动画)
头像加载功能求助:加载中动画替换+显示异常修复
需求描述
需要实现用户头像展示页面:
- 从数据库加载头像耗时约2秒,加载过程显示圆形加载动画GIF
- 头像加载完成后自动替换加载动画为用户头像
状态说明:
- 加载中:圆形旋转动画
- 加载完成:正常用户头像
- 当前异常:头像显示为破损占位符,浏览器弹出资源加载警告
现有后端代码
控制器代码
<HttpGet> Public Async Function ProfilePicture(ByVal UserId As Integer) As Task(Of ActionResult) Using oUser As New User oUser.UserID = UserId Dim oData As Byte() = Await oUser.RetrievePicFromDb If oData IsNot Nothing AndAlso oData.Length > 0 Then Return File(oData, "image/jpg", "") Else Return File("~/Content/Images/default-profile.png", "image /jpg", "") End If End Using End Function
数据库读取代码
Public Async Function RetrievePicFromDb() As Task(Of Byte()) Dim b As Byte() Try Using cn As New SqlClient.SqlConnection cn.ConnectionString = ConfigurationManager.ConnectionStrings("SQLServer").ConnectionString cn.Open() Dim oCmd As New SqlClient.SqlCommand oCmd.Connection = cn oCmd.CommandType = CommandType.Text oCmd.Parameters.Clear() oCmd.Parameters.AddWithValue("@UserID", UserID) oCmd.CommandText = "Select Picture From Users Where UserID = @UserID" Dim iCol As Integer = 0 Dim oReader As SqlClient.SqlDataReader = oCmd.ExecuteReader oReader.Read() Dim bImageByte(oReader.GetBytes(iCol, 0, Nothing, 0, Integer.MaxValue) - 1) As Byte oReader.GetBytes(iCol, 0, bImageByte, 0, bImageByte.Length) Dim ms As New System.IO.MemoryStream(bImageByte) Using ms Dim jpgMS = New System.IO.MemoryStream Dim jpgImage As System.Drawing.Image = System.Drawing.Image.FromStream(ms) jpgImage.Save(jpgMS, System.Drawing.Imaging.ImageFormat.Jpeg) b = jpgMS.ToArray() End Using oReader.Close() cn.Close() End Using Return b Catch ex As Exception Return Nothing End Try End Function
当前问题
- 浏览器提示资源加载警告(无效的MIME类型或资源路径错误)
- 用户头像显示为破损占位符,无法正常渲染
解决方案
前端部分:实现加载中动画替换逻辑
在页面中先放置加载动画,通过JS异步请求头像接口完成替换:
<img id="user-avatar" src="/Content/Images/loading-spinner.gif" alt="加载中" /> <script> document.addEventListener('DOMContentLoaded', function() { const avatarImg = document.getElementById('user-avatar'); // 替换为实际的用户ID和接口路由 fetch(`/YourControllerName/ProfilePicture?UserId=1`) .then(response => { if (!response.ok) throw new Error('加载失败'); return response.blob(); }) .then(blob => { avatarImg.src = URL.createObjectURL(blob); avatarImg.alt = "用户头像"; }) .catch(() => { // 加载失败时显示默认头像 avatarImg.src = "/Content/Images/default-profile.png"; avatarImg.alt = "默认头像"; }); }); </script>
后端代码修复
1. 控制器代码修复
- 修正MIME类型的空格错误(
image /jpg→image/jpeg) - 默认头像使用
Server.MapPath解析物理路径,避免路径错误 - PNG格式默认头像对应MIME类型改为
image/png
<HttpGet> Public Async Function ProfilePicture(ByVal UserId As Integer) As Task(Of ActionResult) Using oUser As New User oUser.UserID = UserId Dim oData As Byte() = Await oUser.RetrievePicFromDb If oData IsNot Nothing AndAlso oData.Length > 0 Then Return File(oData, "image/jpeg", "") Else Dim defaultImgPath = Server.MapPath("~/Content/Images/default-profile.png") Return File(defaultImgPath, "image/png", "") End If End Using End Function
2. 数据库读取代码修复
- 使用异步数据库操作(
OpenAsync、ExecuteReaderAsync、ReadAsync)避免线程阻塞 - 处理用户不存在/无头像的情况(
oReader.Read()返回False) - 用
Using包裹SqlDataReader自动释放资源,无需手动关闭 - 增加图片转换失败的 fallback,直接返回原始字节数组
Public Async Function RetrievePicFromDb() As Task(Of Byte()) Try Using cn As New SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("SQLServer").ConnectionString) Await cn.OpenAsync() Using oCmd As New SqlClient.SqlCommand("Select Picture From Users Where UserID = @UserID", cn) oCmd.Parameters.AddWithValue("@UserID", UserID) Using oReader As SqlClient.SqlDataReader = Await oCmd.ExecuteReaderAsync() If Await oReader.ReadAsync() Then Dim imageLength = oReader.GetBytes(0, 0, Nothing, 0, Integer.MaxValue) If imageLength > 0 Then Dim bImageByte(imageLength - 1) As Byte oReader.GetBytes(0, 0, bImageByte, 0, bImageByte.Length) ' 尝试转换为JPEG,失败则返回原始数据 Try Using ms As New System.IO.MemoryStream(bImageByte) Using jpgImage As System.Drawing.Image = System.Drawing.Image.FromStream(ms) Using jpgMS As New System.IO.MemoryStream jpgImage.Save(jpgMS, System.Drawing.Imaging.ImageFormat.Jpeg) Return jpgMS.ToArray() End Using End Using End Using Catch Return bImageByte End Try End If End If End Using End Using End Using Return Nothing Catch ex As Exception Return Nothing End Try End Function
问题原因说明
- 浏览器警告:MIME类型包含空格(
image /jpg)导致无效,或默认头像路径未正确解析 - 头像显示异常:数据库读取时未处理用户不存在的情况,或图片转换过程中出错导致字节数组损坏
内容的提问来源于stack exchange,提问作者Jkyle Landicho
相关产品推荐
相关产品推荐

