ShowMeBug often has users using a strange browser to open a link to a video interview and have audio and video problems.

After multiple checks, it is found that once the audio and video functions of the product use the WebRTC feature of the browser, it will have particularly high requirements on the browser. If it is not within the range supported by the normal browser, it is prone to problems. So when we detect this problem, there are usually two ways to identify the browser model and version.

The first method: use Modernizr to carry out feature detection and judge whether WebRTC can be used by detecting the existence of these apis. After all, WebRTC is composed of browser APIS.

WebRTC is a fairly new technology that only became an official standard in January, but currently only supports some browsers and needs to be more stable.

The World Wide Web Consortium (W3C) and the Internet Engineering Task Force (IETF) announced today that Web Real-Time Communications (WebRTC), which powers myriad services, is now an official standard, bringing audio and video communications anywhere on the Web.

In January, the W3C and IETF announced that WebRTC, which supports countless services, is now an official standard.

— — 2021.01.26

Network Real-time communication (WebRTC) has changed the communication pattern; It is a World Wide Web Consortium (W3C) recommendation and a number of Internet Engineering Task Force (IETF) standards

Obviously, feature detection does not meet our application scenarios and currently does not meet our requirements, so this method passes.

The second method, which is also the one we are currently using, is to detect user-Agent.

curl http://202.38.95.46:12001/ -H "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) HEICORE/49.1.2623.213 Safari/537.36"
Copy the code

What is the user-agent

Users cannot directly obtain information on the Internet, but need a software as a carrier to represent the User’s behavior. This software is User-Agent, and browser is a typical User-Agent.

Users use different software to do the same thing with a unified protocol. This is also defined in HTTP requests, and every HTTP request must carry a User-Agent header.

The server of a website can determine what browser a User is using through the User-Agent header, and of course can provide differentiated services based on the user-Agent content.

Standard Grammar and history

The original user-Agent browser syntax is very clear

User-Agent: <product> / <product-version> <comment>
Copy the code

User-Agent – HTTP | MDN

Browser implementations were different during the browser wars, because user-Agent content could be used to provide differentiated services. Mozilla (the predecessor to Firefox) was the strongest browser in the world, and many sites only offered high-quality services to Mozilla, until some people disguised themselves as Mozilla (yes, Internet Explorer started). Mozilla/5.0 has since become the first phase of user-Agent.

History of the browser user-agent string

Subsequent browsing has expanded on this, as it does today:

Linux / Firefox

Mozilla / 5.0 (X11; Linux x86_64; The rv: 89.0) Gecko / 20100101 Firefox 89.0Copy the code

Mac OS / Safari

Mozilla / 5.0 (Macintosh; Intel Mac OS X 11_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15Copy the code

Chromium OS / Chrome

Mozilla / 5.0 (X11; CrOS x86_64 13904.16.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.25 Safari/537.36Copy the code

Windows / Edge

Mozilla / 5.0 (Windows NT 10.0; Win64; X64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4482.0 Safari/ 537.36EDG /92.0.874.0Copy the code

This makes it very difficult to identify user-agent. At present, the recognition is basically to use regular expressions with their user-Agent library to judge.

There are a lot of libraries for this, and after a lot of comparisons, this library is relatively full of UA-Parser-JS

At present, almost all web site recognition browsers are user-agent to judge, there are two interfaces:

The front-end has a browser interface:

window.navigator.userAgent
Copy the code

The backend can retrieve the User-Agent through the HTTP request header of the browser

user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10 _15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.04515.107. Safari/537.36
Copy the code

How to use user-Agent

On the mobile terminal, due to the problem of computing power, some old processors will also lag. However, we can run the Benchmark in the browser to determine whether the computing power is sufficient. The user-Agent on the mobile terminal carries processor information (you can check the database to determine).

So, what you’re doing right now is detecting the user’s browser — > prompting it and displaying a list of supports on the document page

Finally, a table is generated using the defined rules:

To reduce future maintenance costs, use a set of data sources that can both detect and generate lists on document pages

Ua-parser-js has a scientific data structure for the returned results, which is reused directly

interface Result {
  ua: string;
  browser: {
    name: string | undefined;
    version: string | undefined;
  };
  device: {
    model: string | undefined;
    type: string | undefined;
    vendor: string | undefined;
  };
  engine: {
    name: string | undefined;
    version: string | undefined;
  };
  os: {
    name: string | undefined;
    version: string | undefined;
  };
  cpu: {
    architecture: string | undefined;
  };
}
Copy the code

So we can define three rules:

  • daily_list(A beta browser)
  • white_list(Tested the browser with no problems)
  • black_list(Browsers with known problems)
// Priority relationship exists: daily_list > white_list > black_list
//
// https://www.npmjs.com/package/ua-parser-js
// @params: ua-parser-js.result
// @params: { <list_name>: <whiteList | blackList>}
// @return: string(list_name)
function browserDetect(ua, list) {
  const { daily_list, white_list, black_list } = list
  if (checkList(ua, daily_list)) return 'daily_list'
  if (checkList(ua, white_list)) return 'white_list'
  if (checkList(ua, black_list)) return 'black_list'
  return ' '
}
Copy the code

Based on this data structure, a simple syntax is added. Support version number judgment, add the support of several symbols: >, ≥, =, <, ≤

Since nothing is readily available, write your own judgment

compare-versions

The configuration file can then be written as config/browser.yml

# https://www.npmjs.com/package/ua-parser-js
#
The syntax of this file is based on the changes made in this library

# whitelist, completely problem-free version
white_list:
  - browser:
      name: "Chrome"
      version: "> = 85.0.0.0"
  - browser:
      name: "Firefox"
      version: "> = 85.0.0.0"
  - browser:
      name: "Edge"
      version: "> = 45.0.0.0"
    device:
      type: "mobile"
    os:
      name: "Android"
      version: "> = 10.0"

black_list:
  # Older versions of Edge are not supported
  - browser:
      name: "Edge"
      version: "< 80.0.0.0"
    os:
      name: "Windows"

  # Mobile wechat built-in browser
  - browser:
      name: "WeChat"
    device:
      type: "mobile"
Copy the code

Users of our products, from geeks who compile their own browsers to Xiaobai who use the Built-in wechat browser, may have problems if they need to give a reminder to detect WebRTC instability in various versions, such as Beta edition, Dev edition, Canary Development edition and nightly Edition.

There was a guy using a developer browser who had audio and video instability during an interview, and it didn’t work out until he got an updated version.

Since the dev browser does not carry the DEV logo in the UA, it can only be determined by the version number. You can use the Caniuse-Lite database to retrieve the version number of the latest stable version and compare the version numbers.

But the Caniuse-Lite database is 1.3m in size and if used directly, the entire database will be packaged. This volume has increased so much that it needs to be optimized, so there is very little data that is actually useful by packing query results into files.

Create a generator that dynamically creates the file latest_browser_list_generator.js

#! /usr/bin/env node

const browserslist = require('browserslist')
const fs = require('fs')

const list = {
  'firefox': true.'chrome': true.'edge': true,}const latest = browserslist("last 1 version").filter(i= > list[i.split(' ') [0]])
fs.writeFileSync('latest_browser_list.js'.`export default The ${JSON.stringify(latest)}`)
Copy the code

Then do these two on a regular basis

  • npx browserslist@latest --update-db
  • node latest_browser_list_generator.js

Of course, this can be done weekly using GitHub Action or GitLab CI

In addition, 360 browser detection method

The 360 browser hides its UA. QIHU 360SE (360 security browser) or QIHU 360EE (360 speed browser) fields will only be carried in UA when visiting its own website (e.g. 360.cn)

360 safety browser and 360 speed browser judgment – V2EX

For domestic browsers (this can detect 360)

GitHub – mumuy/browser: Useragent analysis tool. Browser analysis tool – User agent and operating system information

However, the authors of this library do not provide direct use of the package, only to extract the core code.

  // https://github.com/mumuy/browser/blob/4a50ee18cc76a5013dea3596bb33fbab9ed584c3/Browser.js#L111-L143
  if (_window.chrome) {
    let chrome_version = u.replace(/^.*Chrome\/([\d]+).*$/.'$1')
    if (_window.chrome.adblock2345 || _window.chrome.common2345) {
      match['2345Explorer'] = true
    } else if (
      _mime('type'.'application/360softmgrplugin') ||
      _mime('type'.'application/mozilla-npqihooquicklogin')
    ) {
      is360 = true
    } else if (chrome_version > 36 && _window.showModalDialog) {
      is360 = true
    } else if (chrome_version > 45) {
      is360 = _mime('type'.'application/vnd.chromium.remoting-viewer')
      if(! is360 && chrome_version >=69) {
        is360 = _mime('type'.'application/hwepass2001.installepass2001') || _mime('type'.'application/asx')}}}/ / correction
  if (match['Mobile']) {
    match['Mobile'] = !(u.indexOf('iPad') > -1)}else if (is360) {
    if (_mime('type'.'application/gameplugin')) {
      match['360SE'] = true
    } else if (
      _navigator &&
      typeof _navigator['connection']! = ='undefined' &&
      typeof _navigator['connection'] ['saveData'] = ='undefined'
    ) {
      match['360SE'] = true
    } else {
      match['360EE'] = true}}Copy the code

A word of caution though: Navigator.mimetypes has been removed from the Web standard (it may not work any more someday)

Navigator.mimeTypes – Web APIs | MDN

Judge 360 version, is to do a version of the corresponding relationship

// https://github.com/mumuy/browser/blob/4a50ee18cc76a5013dea3596bb33fbab9ed584c3/Browser.js#L283-L292
function get360SEVersion(u) {
  let hash = { '86': '13.0'.'78': '12.0'.'69': '11.0'.'63': '10.0'.'55': '9.1'.'45': '8.1'.The '42': '8.0'.'and': '7.0'.'21': '6.3' }
  let chrome_version = u.replace(/^.*Chrome\/([\d]+).*$/.'$1')
  return hash[chrome_version] || ' '
}
function get360EEVersion(u) {
  let hash = { '86': '13.0'.'78': '12.0'.'69': '11.0'.'63': '9.5'.'55': '9.0'.'50': '8.7'.'30': '7.5' }
  let chrome_version = u.replace(/^.*Chrome\/([\d]+).*$/.'$1')
  return hash[chrome_version] || ' '
}
Copy the code

The last

While we’ve shared our tips on how to scientifically identify and detect a user’s browser, for the sake of a healthy web environment and avoiding a repeat of the browser wars, we urge you not to offer browser-specific differentiated content.