Просмотр исходного кода

fix(ui) Send preload requests to region urls v2 (#59187)

Our organization preloading was not using region scoped URLs. This
results in slower requests in the test silo environment, and incorrect
requests being made in dev-ui mode.

For the dev-ui environment, I've moved preloading to happen after
client-config is fetched. This ensures that the necessary context has
been fetched to make requests to the correct location.

The changes in https://github.com/getsentry/sentry/pull/59043 didn't
include `withCredentials` resulting in the preload requests failing
which these changes address.
Mark Story 1 год назад
Родитель
Сommit
7f6ccde473

+ 1 - 3
src/sentry/templates/sentry/layout.html

@@ -50,9 +50,7 @@
   </script>
   {% endscript %}
 
-  {% script %}
-    {% include "sentry/partial/preload-data.html" %}
-  {% endscript %}
+  {% include "sentry/partial/preload-data.html" %}
 
   {% block scripts %}
   {% block scripts_main_entrypoint %}

+ 30 - 16
src/sentry/templates/sentry/partial/preload-data.html

@@ -1,13 +1,26 @@
+{% load sentry_assets %}
+
+{% script %}
 <script type="text/javascript">
-  try {
-    var reg = new RegExp(/\/organizations\/(.+?(?=(\/|$)))(\/|$)/, 'i');
-    var organization = window.location.pathname;
-    var slug = organization.match(reg)[1];
+  function __preloadData() {
+    if (!window.__initialData.user) {
+      // Don't send requests if there is no logged in user.
+      return;
+    }
+    var slug = window.__initialData.lastOrganization;
+    if (!slug && window.__initialData.customerDomain) {
+      slug = window.__initialData.customerDomain.subdomain;
+    }
+    var host = '';
+    if (window.__initialData.links && window.__initialData.links.regionUrl !== window.__initialData.links.sentryUrl) {
+      var host = window.__initialData.links.regionUrl;
+    }
 
     function promiseRequest(url) {
       return new Promise(function (resolve, reject) {
         var xhr = new XMLHttpRequest();
         xhr.open('GET', url);
+        xhr.withCredentials = true;
         xhr.onload = function () {
           try {
             this.status >= 200 && this.status < 300
@@ -25,20 +38,21 @@
     }
 
     function makeUrl(suffix) {
-      return '/api/0/organizations/' + slug + suffix;
+      return host + '/api/0/organizations/' + slug + suffix;
     }
 
-    // There are probably more, but this is at least one case where
-    // this should not be treated as a slug
-    if (slug !== 'new') {
-      var preloadPromises = {orgSlug: slug};
-      window.__sentry_preload = preloadPromises;
+    var preloadPromises = {orgSlug: slug};
+    window.__sentry_preload = preloadPromises;
 
-      preloadPromises.organization = promiseRequest(makeUrl('/?detailed=0'));
-      preloadPromises.projects = promiseRequest(
-        makeUrl('/projects/?all_projects=1&collapse=latestDeploys')
-      );
-      preloadPromises.teams = promiseRequest(makeUrl('/teams/'));
-    }
+    preloadPromises.organization = promiseRequest(makeUrl('/?detailed=0'));
+    preloadPromises.projects = promiseRequest(
+      makeUrl('/projects/?all_projects=1&collapse=latestDeploys')
+    );
+    preloadPromises.teams = promiseRequest(makeUrl('/teams/'));
+  }
+
+  try {
+    __preloadData();
   } catch (_) {}
 </script>
+{% endscript %}

+ 67 - 1
static/app/bootstrap/index.tsx

@@ -34,7 +34,73 @@ async function bootWithHydration() {
   }
   window.__initialData = data;
 
-  return bootApplication(data);
+  bootApplication(data);
+  preloadOrganizationData(data);
+
+  return data;
+}
+
+function promiseRequest(url: string): Promise<any> {
+  return new Promise(function (resolve, reject) {
+    const xhr = new XMLHttpRequest();
+    xhr.open('GET', url);
+    xhr.withCredentials = true;
+    xhr.onload = function () {
+      try {
+        this.status >= 200 && this.status < 300
+          ? resolve([JSON.parse(xhr.response), this.statusText, xhr])
+          : reject([this.status, this.statusText]);
+      } catch (e) {
+        reject();
+      }
+    };
+    xhr.onerror = function () {
+      reject([this.status, this.statusText]);
+    };
+    xhr.send();
+  });
+}
+
+function preloadOrganizationData(config: Config) {
+  if (!config.user) {
+    // Don't send requests if there is no logged in user.
+    return;
+  }
+  let slug = config.lastOrganization;
+  if (!slug && config.customerDomain) {
+    slug = config.customerDomain.subdomain;
+  }
+
+  let host = '';
+  if (config.links?.regionUrl && config.links?.regionUrl !== config.links?.sentryUrl) {
+    host = config.links.regionUrl;
+  }
+  // When running in 'dev-ui' mode we need to use /region/$region instead of
+  // subdomains so that webpack/vercel can proxy requests.
+  if (host && window.__SENTRY_DEV_UI) {
+    const domainpattern = /https?\:\/\/([^.]*)\.sentry.io/;
+    const domainmatch = host.match(domainpattern);
+    if (domainmatch) {
+      host = `/region/${domainmatch[1]}`;
+    }
+  }
+
+  function makeUrl(suffix: string) {
+    return host + '/api/0/organizations/' + slug + suffix;
+  }
+
+  const preloadPromises: Record<string, any> = {orgSlug: slug};
+  window.__sentry_preload = preloadPromises;
+  try {
+    preloadPromises.organization = promiseRequest(makeUrl('/?detailed=0'));
+    preloadPromises.projects = promiseRequest(
+      makeUrl('/projects/?all_projects=1&collapse=latestDeploys')
+    );
+    preloadPromises.teams = promiseRequest(makeUrl('/teams/'));
+  } catch (e) {
+    // eslint-disable-next-line
+    console.error(e);
+  }
 }
 
 /**

+ 1 - 1
static/app/index.tsx

@@ -30,7 +30,7 @@
 //
 // 3. App initialization does the following...
 //
-//   a. Initialize the ConfigStore with clinet-config data.
+//   a. Initialize the ConfigStore with client-config data.
 //
 //   b. Initialize the Sentry SDK. This includes setting up integrations for
 //      routing and tracing.

+ 5 - 0
static/app/types/system.tsx

@@ -73,6 +73,11 @@ declare global {
      * Assets public location
      */
     __sentryGlobalStaticPrefix: string;
+    /**
+     * Is populated with promises/strings of commonly used data.
+     */
+    __sentry_preload: Record<string, any>;
+
     // typing currently used for demo add on
     // TODO: improve typing
     SentryApp?: {

+ 0 - 63
static/index.ejs

@@ -12,69 +12,6 @@
       }
       __sentryMark('head-start');
     </script>
-    <script type="text/javascript">
-    try {
-      function extractSlug() {
-        // XXX: If you change this also change its sibilings in:
-        // - static/app/utils/extractSlug.tsx
-        // - webpack.config.ts
-        // NB: This RegExp is not exactly the same as the other two
-        var knownDomains = /\.(?:localhost|dev\.getsentry\.net|sentry\.dev)(?:\:\d*)?$/;
-        if (window.location.host.match(knownDomains)) {
-          var domainParts = window.location.host.split('.');
-          var slug = domainParts.shift();
-          return slug;
-        }
-
-        var pathReg = /\/organizations\/(.+?(?=(\/|$)))(\/|$)/i;
-        var matches = pathReg.exec(window.location.pathname);
-        if (matches) {
-          return matches[1];
-        }
-
-        console.error(`Could not extract an organization slug from ${window.location}. Assuming 'sentry'`);
-
-        return 'sentry';
-      }
-
-      var slug = extractSlug();
-      var preloadPromises = { orgSlug: slug };
-
-      function promiseRequest(url) {
-        return new Promise(function (resolve, reject) {
-          var xhr = new XMLHttpRequest();
-          xhr.open('GET', url);
-          xhr.onload = function () {
-            try {
-              this.status >= 200 && this.status < 300
-                ? resolve([JSON.parse(xhr.response), this.statusText, xhr])
-                : reject([this.status, this.statusText]);
-            } catch(e) {
-              reject();
-            }
-          };
-          xhr.onerror = function () {
-            reject([this.status, this.statusText]);
-          };
-          xhr.send();
-        });
-      }
-
-      function makeUrl(suffix) {
-        return '/api/0/organizations/' + slug + suffix;
-      }
-
-      window.__sentry_preload = preloadPromises;
-
-      if (slug !== 'new') {
-        preloadPromises.organization = promiseRequest(makeUrl('/?detailed=0'));
-        preloadPromises.projects =  promiseRequest(makeUrl('/projects/?all_projects=1&collapse=latestDeploys'));
-        preloadPromises.teams = promiseRequest(makeUrl('/teams/'));
-      }
-    } catch(err) {
-      console.error(err)
-    }
-    </script>
   </head>
 
   <body>