React.js + TypeScript项目中BrowserRouter访问带末尾斜杠的子路径时出现SyntaxError: Unexpected token '<'的问题解决
问题描述
我用React.js(+TypeScript)做了一个网站,里面集成的Unity WebGL构建原本运行正常。
[EDIT 1] 网站用create-react-app构建,本地托管在
https://localhost:3001。
[EDIT 2] 在WebStorm中通过npm run start启动。
index.html和App.tsx关联正常,后来我给网站添加了Router,路由设置如下:
- "website.com/"
- "website.com/ping"
- "website.com/ping/"
第一个和第二个路由都没问题,但当路径末尾多了一个斜杠时,整个页面就崩了,会连续三次出现错误:SyntaxError: Unexpected token '<'。
打开DevTools查看后,发现关键错误是:Build WebGL.loader.js:1 Uncaught SyntaxError: Unexpected token '<' (at Build WebGL.loader.js:1:1)
[EDIT 2] 注:看起来这个问题本质和WebGL无关。
后来我发现问题和斜杠有关,通过DevTools的Sources标签对比了两个路径的加载情况:
- 访问"website.com/ping"时,Unity WebGL构建文件的路径是正常的:

- 访问"website.com/ping/"时,构建文件的路径被搞乱了:

相关代码(App.tsx片段)
enum gameIds{ INSOMNIAC_MOLES = "GAME-INSOMNIAC_MOLES", } interface GameSegmentProps{ gameId: string; } const GameSegment = ({gameId}: GameSegmentProps) => { return <div>W.I.P: Game: {gameId}</div>; }; <BrowserRouter> <Routes> <Route path="/" element={<WipSegment/>} /> <Route path="/ping" element={<div>Pong!</div>} /> <Route path="/test" element={<GameSegment gameId={gameIds.INSOMNIAC_MOLES}/>} /> <Route path="/games/insomniac_moles" element={<GameSegment gameId={gameIds.INSOMNIAC_MOLES}/>} /> <Route path="*" element={<p>hhjalp</p>} /> </Routes> </BrowserRouter>
错误截图
[EDIT 1]
网站内错误截图:
DevTools错误截图:
问题原因分析
兄弟,这个问题我之前也碰到过!本质就是相对路径加载资源搞出的锅。当你访问带末尾斜杠的路径(比如/ping/)时,浏览器会把这个路径当成一个"子目录",这时候页面里所有用相对路径引入的资源(比如你的Unity WebGL构建文件、JS/CSS这些)都会以/ping/为基准去找,而不是网站的根目录。但这些资源实际是放在根目录下的啊!所以浏览器加载到的根本不是预期的JS文件,而是React返回的404页面(HTML内容),JS解析器一看到HTML的<肯定懵了,就抛出那个Unexpected token '<'错误了。
解决方案
给你几个靠谱的解决办法,按好用程度排的:
1. 给BrowserRouter加basename(首推)
在BrowserRouter里指定basename为网站根路径,这样所有路由都会以根目录为基准,不管路径有没有末尾斜杠都不会乱:
<BrowserRouter basename="/"> {/* 你的路由配置原样放这里就行 */} </BrowserRouter>
要是以后你的网站部署在子目录下,比如https://example.com/my-game/,就把basename改成/my-game/就行,很灵活。
2. 把所有资源路径改成绝对路径
不管是Unity的构建文件,还是项目里的CSS、JS引入,全都改成以/开头的绝对路径。比如原本写的./Build/WebGL.loader.js,改成/Build/WebGL.loader.js,这样浏览器不管当前在哪个路由下,都会直接从根目录找资源,绝对不会错。
3. 服务器端配置重定向(部署的时候用)
如果是生产环境部署,你可以让服务器把带末尾斜杠的路径自动重定向到不带斜杠的版本。比如用Nginx的话,加这么一条规则:
rewrite ^/(.*)/$ /$1 permanent;
本地开发的话,直接改package.json里的start命令,加上PUBLIC_URL环境变量:
"scripts": { "start": "PUBLIC_URL=/ react-scripts start" }
这样本地跑的时候,资源也会以根目录为基准加载。
4. 换成HashRouter(备选)
要是上面的方法都不想搞,也可以试试用HashRouter代替BrowserRouter,它的URL会带个#,比如website.com/#/ping/,这种情况下浏览器不会把路径当成子目录,资源加载就不会乱。就是URL看起来有点丑,适合对URL美观度要求不高的场景。
备注:内容来源于stack exchange,提问作者Blawnode



