Skip to content

Commit

Permalink
[React][Vue][Angular] Ensure keep-alive agent is used throughout samp…
Browse files Browse the repository at this point in the history
…le apps for server-side web requests (#463)
  • Loading branch information
sc-illiakovalenko authored Oct 15, 2020
1 parent c5571d8 commit e6e556a
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 32 deletions.
9 changes: 9 additions & 0 deletions samples/angular/server.bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { readFileSync } from 'fs';
import { JssRouteBuilderService } from './src/app/routing/jss-route-builder.service';
import { environment } from './src/environments/environment';

const http = require('http');
const https = require('https');

// Our index.html we'll use as our template
const template = readFileSync(join(__dirname, 'browser', 'index.html')).toString();
Expand All @@ -14,6 +16,12 @@ const template = readFileSync(join(__dirname, 'browser', 'index.html')).toString
const { AppServerModule, renderModule } = require('./dist/server/main');


// Setup Http/Https agents for keep-alive. Used in headless-proxy
const setUpDefaultAgents = (httpAgent, httpsAgent) => {
http.globalAgent = httpAgent;
https.globalAgent = httpsAgent;
};

// this is the function expected by the JSS View Engine for "integrated mode"
function renderView (callback, path, data, viewBag) {
try {
Expand Down Expand Up @@ -81,6 +89,7 @@ function parseRouteUrl(url) {
module.exports = {
renderView,
parseRouteUrl,
setUpDefaultAgents,
apiKey: environment.sitecoreApiKey,
appName: environment.jssAppName
};
41 changes: 11 additions & 30 deletions samples/node-headless-ssr-proxy/config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const fs = require('fs');
const keepAlive = require("agentkeepalive");
const fetch = require('node-fetch');
const NodeCache = require('node-cache');
const httpAgents = require("./httpAgents");

// We keep a cached copy of the site dictionary for performance. Default is 60 seconds.
const dictionaryCache = new NodeCache({ stdTTL: 60 });
Expand All @@ -19,36 +19,12 @@ const bundlePath = process.env.SITECORE_JSS_SERVER_BUNDLE || `./dist/${appName}/

const serverBundle = require(bundlePath);

httpAgents.setUpDefaultAgents(serverBundle);

const apiHost = process.env.SITECORE_API_HOST || 'http://my.sitecore.host'

appName = appName || serverBundle.appName;

/**
* Enable connection pooling. Adds `connection: keep-alive` header
* @param {string} apiHost sitecore api host
*/
const keepAliveAgent = (apiHost) => {
const keepAliveConfig = {
maxSockets: 200,
maxFreeSockets: 20,
timeout: 240 * 1000,
freeSocketTimeout: 240 * 1000,
};

if (!apiHost) {
throw new Error("[KEEP-ALIVE-CONFIG] SITECORE_API_HOST value is required, but was undefined")
}

if (!apiHost.indexOf("http://")) return new keepAlive(keepAliveConfig);

if (!apiHost.indexOf("https://")) return new keepAlive.HttpsAgent(keepAliveConfig);

throw new Error(
"[KEEP-ALIVE-CONFIG] Unexpected SITECORE_API_HOST value, expected http:// or https://, but was " +
apiHost
);
}

/**
* @type {ProxyConfig}
*/
Expand Down Expand Up @@ -110,8 +86,8 @@ const config = {
* Options object for http-proxy-middleware. Consult its docs.
*/
proxyOptions: {
// Enable connection pooling
agent: keepAliveAgent(apiHost),
// Enable connection pooling
agent: httpAgents.getAgent(apiHost),
// Setting this to false will disable SSL certificate validation
// when proxying to a SSL Sitecore instance.
// This is a major security issue, so NEVER EVER set this to false
Expand Down Expand Up @@ -170,7 +146,12 @@ const config = {
return fetch(
`${config.apiHost}/sitecore/api/jss/dictionary/${appName}/${language}?sc_apikey=${
config.apiKey
}`
}`,
{
headers: {
connection: "keep-alive",
},
}
)
.then((result) => result.json())
.then((json) => {
Expand Down
42 changes: 42 additions & 0 deletions samples/node-headless-ssr-proxy/httpAgents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const keepAlive = require("agentkeepalive");
const http = require("http");
const https = require("https");

const keepAliveConfig = {
maxSockets: 200,
maxFreeSockets: 20,
timeout: 240 * 1000,
freeSocketTimeout: 240 * 1000,
};

const httpAgent = new keepAlive(keepAliveConfig);
const httpsAgent = new keepAlive.HttpsAgent(keepAliveConfig);

module.exports = {
setUpDefaultAgents: (serverBundle) => {
http.globalAgent = httpAgent;
https.globalAgent = httpsAgent;

if (serverBundle.setUpDefaultAgents) {
serverBundle.setUpDefaultAgents(httpAgent, httpsAgent);
}
},
/**
* Enable connection pooling. Adds `connection: keep-alive` header
* @param {string} url api host
*/
getAgent: (url) => {
if (!url) {
throw new Error("[KEEP-ALIVE-CONFIG] SITECORE_API_HOST value is required, but was undefined")
}

if (!url.indexOf("http://")) return httpAgent;

if (!url.indexOf("https://")) return httpsAgent;

throw new Error(
"[KEEP-ALIVE-CONFIG] Unexpected SITECORE_API_HOST value, expected http:// or https://, but was " +
url
);
},
};
12 changes: 12 additions & 0 deletions samples/react/server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import React from 'react';
import { StaticRouter, matchPath } from 'react-router-dom';
import { renderToStringWithData } from 'react-apollo';
import Helmet from 'react-helmet';
import axios from "axios";
import http from "http";
import https from "https";
import GraphQLClientFactory from '../src/lib/GraphQLClientFactory';
import config from '../src/temp/config';
import i18ninit from '../src/i18n';
Expand All @@ -26,6 +29,15 @@ function assertReplace(string, value, replacement) {
return result;
}

// Setup Http/Https agents for keep-alive. Used in headless-proxy
export const setUpDefaultAgents = (httpAgent, httpsAgent) => {
axios.defaults.httpAgent = httpAgent;
axios.defaults.httpsAgent = httpsAgent;

http.globalAgent = httpAgent;
https.globalAgent = httpsAgent;
};

/** Export the API key. This will be used by default in Headless mode, removing the need to manually configure the API key on the proxy. */
export const apiKey = config.sitecoreApiKey;

Expand Down
8 changes: 7 additions & 1 deletion samples/react/src/lib/GraphQLClientFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ import { createPersistedQueryLink } from 'apollo-link-persisted-queries';
export default function (endpoint, ssr, initialCacheState) {
/* HTTP link selection: default to batched + APQ */
const link = createPersistedQueryLink().concat(
new BatchHttpLink({ uri: endpoint, credentials: 'include' })
new BatchHttpLink({
uri: endpoint,
credentials: 'include',
headers: {
connection: "keep-alive"
}
})
);

const cache = new InMemoryCache({
Expand Down
12 changes: 12 additions & 0 deletions samples/vue/server/server.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import Vue from 'vue';
import { createRenderer } from 'vue-server-renderer';
import serializeJavascript from 'serialize-javascript';
import axios from "axios";
import http from "http";
import https from "https";
import i18ninit from '../src/i18n';
import { createApp } from '../src/createApp';
import { createRouter } from '../src/router';
Expand Down Expand Up @@ -28,6 +31,15 @@ function assertReplace(string, value, replacement) {
return result;
}

// Setup Http/Https agents for keep-alive. Used in headless-proxy
export const setUpDefaultAgents = (httpAgent, httpsAgent) => {
axios.defaults.httpAgent = httpAgent;
axios.defaults.httpsAgent = httpsAgent;

http.globalAgent = httpAgent;
https.globalAgent = httpsAgent;
};

/** Export the API key. This will be used by default in Headless mode, removing the need to manually configure the API key on the proxy. */
export const apiKey = config.sitecoreApiKey;

Expand Down
8 changes: 7 additions & 1 deletion samples/vue/src/lib/GraphQLClientFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ import { createPersistedQueryLink } from 'apollo-link-persisted-queries';
export default function(endpoint, ssr, initialCacheState) {
/* HTTP link selection: default to batched + APQ */
const link = createPersistedQueryLink().concat(
new BatchHttpLink({ uri: endpoint, credentials: 'include' })
new BatchHttpLink({
uri: endpoint,
credentials: 'include',
headers: {
connection: "keep-alive"
}
})
);
// basic HTTP link
// const link = createHttpLink({ uri: endpoint, credentials: 'include' });
Expand Down

0 comments on commit e6e556a

Please sign in to comment.