Saw this on SO and reproduced.
You can repro this with the following:
// app.js
'use strict'
const express = require('express');
const horizon = require('@horizon/server');
const app = express();
app.use(express.static('public'));
const http_server = app.listen(8181);
const options = { permissions: false, auth: {allow_anonymous: true, allow_unauthenticated: true, token_secret:'test'} };
const horizon_server = horizon(http_server, options);
console.log('Listening on port 8181.');
<!-- public/index.html -->
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<script src="http://localhost:8181/horizon/horizon.js"></script>
<script>
var horizon = Horizon({authType: 'anonymous'});
horizon.onReady(function() {
document.querySelector('h1').innerHTML = 'App works!'
});
horizon.connect();
</script>
</head>
<body>
<marquee><h1></h1></marquee>
</body>
</html>

Attempting to use wsta or just `new WebSocket("localhost:8181/horizon") doesn't work either but not sure if that's expected since it's the engine.io server not vanilla websockets.
i've finally been able to figure out why these 400 / bad requests happen. at least in my case.
due to engine.ios transport upgrade, it first uses xhr and then switches to websockets if available.
now, if your server is not configured to handle this correctly, it can lead to the aforementioned 400 - Bad Request.
Also see: https://github.com/socketio/socket.io/issues/1696
In my case, I was able to work around this issue by using this in my Apache config:
<Location /horizon>
RewriteEngine on
RewriteCond %{QUERY_STRING} transport=polling
RewriteRule /(.*)$ http://localhost:2000/horizon/$1 [P]
ProxyPass ws://localhost:2000/horizon
ProxyPassReverse ws://localhost:2000/horizon
</Location>
Of course, it largely depends on your setup, but I'm pretty sure that these 400s all came from such a server config issue.
That's good news then, maybe the websockets fix will get us this for free
Struggling with the same issue, when will this be released ?
Can confirm that this now works with the current master.
Probably due to the removal of engine.io in #526.
Should add that I then ran into CORS issues and after that into the POST simply failing :S
Is this still relevant now that engine.io is out @deontologician?
Yeah, this can probably be closed.
Most helpful comment
Struggling with the same issue, when will this be released ?