Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Is there a way to set the Connection: keep-alive #131

Closed
CoffeeWasabi opened this issue Feb 22, 2023 · 8 comments
Closed

Question: Is there a way to set the Connection: keep-alive #131

CoffeeWasabi opened this issue Feb 22, 2023 · 8 comments

Comments

@CoffeeWasabi
Copy link

CoffeeWasabi commented Feb 22, 2023

Hi!
I'm using nuxt and trying to http communicate using mockttp.
The environment is as follows.

  • frontend and backend
    • node.js : v19.3.0
  • frontend
    • nuxt : 3.1.0
    • vue-router : 4.1.6
  • backend
    • mockttp 3.6.2
    • ts-node : 10.9.1

Client side source is as follows.

<script setup lang="ts">
const submit = async () => {
    const{ data, error } = await useFetch("/api/submit", {
        method: "POST",
        baseURL: "http://localhost:3001",
    });
}
</script>
<template>
    <div>
        <p>submit test</p>
        <button v-on:click="submit">submit</button>
     </div>
</template>

Server source with mockttp is as follows.

import {getLocal} from "mockttp"

const HEADERS_OPTIONS = {
    "Access-Control-Allow-Headers": "Content-Type, Authorization",
    "Access-Control-Allow-Methods": "GET, OPTIONS, POST",
    // CORS
    "Access-Control-Allow-Origin": "http://localhost:3000",
    "Access-Control-Allow-Credentials": "true",
};

const basePath = "/api";
const mockServer = getLocal({
    debug:true,
});

const port = Number(3001);

mockServer.start(port).then();
mockServer.forOptions().thenReply(204, "", {...HEADERS_OPTIONS});
mockServer.forGet("/").thenReply(200);
mockServer
    .forPost(basePath + "/submit")
    .thenJson(
        200,
        {
            result: "success",
            messages: "message",
        },
        {...HEADERS_OPTIONS}
);

I started the cliend and server and pressed submit button.
The network results are as follows.
Network results

This is the result in chrome, but when I do it in safari I get a 500 error.

One thing that annoys me is that Connection: keep-alive is not set in the response.
I have a question, is it possible to set Connection: keep-alive with mockttp?

Thank you.

@pimterry
Copy link
Member

This is the result in chrome, but when I do it in safari I get a 500 error.

I'm not sure why that would happen, can you share the details of the 500 error? A HAR of the request and the debug output from Mockttp might also be useful.

is it possible to set Connection: keep-alive with mockttp?

Yes, you just need to put connection: 'keep-alive' in your HEADERS_OPTIONS. If you don't specify custom headers then Mockttp will use standard defaults (including Connection: keep-alive, but as soon as you specify your own headers you need to specify all the headers you want included.

@CoffeeWasabi
Copy link
Author

@pimterry
Thank you for your prompt reply.

Yes, you just need to put connection: 'keep-alive' in your HEADERS_OPTIONS. If you don't specify custom headers then Mockttp will use standard defaults (including Connection: keep-alive, but as soon as you specify your own headers you need to specify all the headers you want included.

Thank you for teaching me.
When i checked with chrome, "Connection: keep-alive" was certainly set in the response.

I'm not sure why that would happen, can you share the details of the 500 error? A HAR of the request and the debug output from Mockttp might also be useful.

I am very sorry.
I don't own the PC on which the error occurs, so it's difficult to share the details.

However, when I tried the method I was taught, I confirmed that I could communicate with safari.
Looking at the behavior, safari may be a specification that blocks communication if Connection is not set in the header.

I'll take a look at this.

@pimterry
Copy link
Member

So it's hard to know, but one thing that could be causing your Safari issue is this Node.js bug: nodejs/node#46321.

Mockttp does remove the connection header, in cases like this where you override the headers and don't specify it. That header isn't actually required though, it's totally unnecessary, so this shouldn't cause problems. For HTTP/1.1+, keep alive is the default if the connection header isn't specified. The bug above though is that Node.js does this incorrectly, and treats 'close' as the default if the header isn't sent. This shouldn't usually be a big issue, but it can confuse some clients, which will expect the connection to stay open, and so when they try to send a second request they will unexpectedly fail when they discover it's closed.

I wouldn't expect this to result in a 500 error, but it's the kind of thing that can create odd errors anyway. If that is the issue, explicitly adding your own connection: keep-alive header will fix it. I've now fixed this in Node itself, but because it's a potentially breaking change that fix won't be available until Node v20, which won't be released until April 2023. Once that's released, this will work correctly (i.e. when there is no Connection header, the connection will still be kept alive) when using Mockttp with those node versions.

@CoffeeWasabi
Copy link
Author

@pimterry
Thank you for your detailed explanation.

I understad that the node.js version that incorporates #46321 will be released around April 2023.
I think it might have something todo with this bug. When node is released, I will import it and check it.

Please ask additional questions.

If you don't specify custom headers then Mockttp will use standard defaults

I understand that to apply the default headers do not set HEADERS_OPTIONS as an argument, is this correct?
When I tried to remove HEADERS_OPTIONS, a CORS error was displayed in the browser console.

Access to fetch at 'http://localhost:3001/api/submit' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Is there any way to solve this other than setting a custom header?

@pimterry
Copy link
Member

Is there any way to solve this other than setting a custom header?

No, to handle CORS you do need to set custom headers. That's fine though! It is possible to use custom headers, you just need to include Connection: keep-alive in your custom headers too, like so:

const HEADERS_OPTIONS = {
    "Access-Control-Allow-Headers": "Content-Type, Authorization",
    "Access-Control-Allow-Methods": "GET, OPTIONS, POST",
    // CORS
    "Access-Control-Allow-Origin": "http://localhost:3000",
    "Access-Control-Allow-Credentials": "true",
    // Enable keep-alive:
    "Connection": "keep-alive" // <-- here
};

Does that make sense?

@CoffeeWasabi
Copy link
Author

@pimterry
I see, I was able to understand by putting CORS settings in the custom header.

Does that make sense?

Yes, i understand. I asked if there was another way to do the above.
I appreciate your time, I know you are very busy.

@pimterry
Copy link
Member

Oh I see, you want a different way to handle CORS? Sorry, I thought you wanted a different way to handle the default headers part, my mistake.

It is possible to do CORS automatically, you can do so by passing a cors option when you create the server, e.g:

// Create a server with default CORS settings all enabled:
getLocal({ cors: true });

// Create a server with custom CORS configuration:
getLocal({
    cors: {
        origin: 'http://example.com', // Only allow this origin
        credentials: true, // Allow credentials with CORS
        allowedHeaders: ['a', 'b'] // Allow specific headers
    }
});

This option gets passed to the cors module, so if you want to configure it you can use any option supported there.

Be aware that if you do this instead of handling CORS yourself, then it will be applied to all requests to this server, and you won't be able to mock OPTIONS requests manually. If you just want to receive everything that's fine, but if you want more precise control you may want to mock requests by hand instead, as you've been doing.

@CoffeeWasabi
Copy link
Author

@pimterry
I am sorry that I asked a question that is not easy to understand.

I see, set it to the cors property of getLocal(), right? I didn't know how to set the CorsOptions, so it was very helpful. When I took it in as a trial and checked it, I confirmed that the error was resolved. Thank you for your instruction!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants