You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

当前问题

  1. 浏览器提示资源加载警告(无效的MIME类型或资源路径错误)
  2. 用户头像显示为破损占位符,无法正常渲染

解决方案

前端部分:实现加载中动画替换逻辑

在页面中先放置加载动画,通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 11:15:43