React中THREE.js GLTFLoader加载gltf报JSON解析错误如何解决
问题根因
报错 SyntaxError: Unexpected token < in JSON at position 0 没有歧义:GLTFLoader加载.gltf文件时,会把拿到的响应内容按JSON格式解析,结果内容第一个字符是<——这说明你请求untitled.gltf的时候,服务器根本没返回gltf文件,返回的是HTML内容(99%的情况是404错误页,所有HTML页面的起始字符基本都是<,比如<!DOCTYPE html>)。
你写的const loader = new GLTFLoader()这行初始化代码本身没有问题,不用在这上面浪费时间排查。
排查方向
按顺序检查即可:
- 先打开浏览器开发者工具的「网络」面板,刷新页面,筛选找到
untitled.gltf这条请求:- 如果状态码是404,就是路径写错了,服务器找不到这个文件所以返回了404的HTML页。
- 如果状态码是200,点进去看「响应」标签,看内容是不是HTML,如果是,还是路径或者静态资源配置的问题,服务器把其他HTML内容当gltf返回了。
- 修正静态资源路径:
从你的代码看是React项目,不管用Vite还是Create React App脚手架,要被前端直接请求的静态文件都要放到项目根目录的public文件夹里,不要放到src目录下,src里的文件会被构建工具打包处理,不会按原文件名对外提供访问。
路径不要写相对路径"untitled.gltf",改成根路径写法"/untitled.gltf"——开头的/代表从站点域名根目录找资源,不会受当前页面路由影响,避免路由嵌套时找错路径。 - 检查文件本身:
找到本地的untitled.gltf,用任意文本编辑器打开,正常gltf是纯JSON格式,开头应该是{,里面能看到"asset": {"version": "2.0"}这类字段,如果打开就是<开头的HTML内容,说明你从建模软件导出gltf的时候操作错了,文件本身存成了网页,重新导出即可。
现有代码的其他必改问题
你贴的代码就算路径对了也跑不起来,有几个基础问题:
- 没有引入
React和Component,类组件直接继承Component会报引用错误 - 没有写渲染循环,模型加载完成后也不会绘制到画布上
- 没有加光源,3D模型没有光照的话渲染出来是纯黑的
- 相机默认位置在(0,0,0),和模型初始位置重合,就算加载完也看不到东西
- 组件卸载时没有清理渲染任务和事件监听,会造成内存泄漏
修复后的完整rende.js代码:
import React, { Component } from "react"; import * as THREE from "three"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; export default class Rende extends Component { componentDidMount() { // 初始化场景 this.scene = new THREE.Scene(); // 初始化相机 this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); this.camera.position.z = 5; // 加光照,不然模型是黑的 this.scene.add(new THREE.DirectionalLight(0xffffff, 1)); this.scene.add(new THREE.AmbientLight(0xffffff, 0.5)); // 初始化渲染器 this.renderer = new THREE.WebGLRenderer({ antialias: true }); this.renderer.setClearColor(0x424242, 1); this.renderer.setSize(window.innerWidth, window.innerHeight); document.getElementById("scene").appendChild(this.renderer.domElement); // 加载模型,注意路径对应public目录下的文件位置 const loader = new GLTFLoader(); loader.load( "/untitled.gltf", (gltf) => { this.scene.add(gltf.scene); }, (xhr) => { console.log(`${((xhr.loaded / xhr.total) * 100).toFixed(2)}% loaded`); }, (error) => { console.error("GLTF load failed:", error); } ); // 启动渲染循环 this.animateId = requestAnimationFrame(this.animate.bind(this)); // 监听窗口大小变化,避免画布拉伸 window.addEventListener("resize", this.handleResize.bind(this)); } handleResize() { this.camera.aspect = window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize(window.innerWidth, window.innerHeight); } animate() { this.renderer.render(this.scene, this.camera); this.animateId = requestAnimationFrame(this.animate.bind(this)); } componentWillUnmount() { // 组件卸载时清理资源 cancelAnimationFrame(this.animateId); window.removeEventListener("resize", this.handleResize.bind(this)); this.renderer.dispose(); } render() { return <div id="scene" className="potato"></div>; } }
内容的提问来源于stack exchange,提问作者squarewatermeln
相关产品推荐
相关产品推荐

