This article has participated in the third “topic writing” track of the Denver Creators Training Camp. For details, check out: Digg Project | Creators Training Camp third is ongoing, “write” to make a personal impact.

Title/ Browser Cross-domain request principles and solutions detailed guide # flight.archives011

Introduction: Recently I saw a new wave of creative activities, the official topic is “why can’t XHR cross-domain request resources “, looks like a very simple interview question hahaha as front-end enthusiasts, might as well take this opportunity to study cross-domain, summarize an article out. So I arranged the flight.a011 FocusList# writing schedule.

Overview: A concise and efficient guide to cross-domain requests made with ❤ by

Note:

  1. XHR represents in this articleXMLHttpRequestObject.
  2. CORS saidCross-origin resource sharingCross-domain resource sharing.
  3. The Request Headers is the Response Headers.

Introduction to Tag/ Browser Cross-domain (CORS) restrictions: Why are XHR cross-domain requests restricted and how can cross-domain restrictions be triggered

Big guys can directly look at the next chapter of the solution, here will be explained in detail to facilitate beginners to start (who have been cute new), do not know CORS to make up for the lesson ~

Cross-domain, where A request from station A accesses the server at Station B. If the protocol, domain, or port are different in any way, the browser thinks they are two different sites, triggering cross-domain security restrictions.

To be specific, it is: [https://][example.com][:80]/path? Query# heading-1 is "homologous" only if the contents in square brackets are identical. The default HTTPS port is 443, and the default HTTP port is 80. The default port can be omitted. That is to say, https://example.com:443/... And https://example.com/... Same as HTTP.Copy the code

->> Why do browsers have cross-domain restrictions

Imagine this scenario: I am an unknown small blogger, and you are visiting my Blog website. Then I suddenly think of sending a request to the server of Weibo with automatic JS program, so that you can automatically follow my microblog. If this can be done, then the browser is too insecure, and the website owner can make many dangerous requests in the background (such as obtaining your login information on Weibo, etc.). So browsers have a cross-domain restriction that prevents unsafe third-party content requests.

Here’s an example:

If I access the front page of my blog park from the Console on the Segmentfault official website, XHR cross-domain restrictions will be triggered, preventing me from reading the returned content.

Another scenario: you are a small webmaster using vue.js on your website and add a CDN script (unpkg, etc.) and the browser error prevents you from using the CDN script because of the cross-domain restriction. This is obviously not reasonable, so today’s browsers will use the access-Control-Allow-Origin attribute in the response header to determine whether you can read the content returned. For example, unpkg sets the access-Control-Allow-Origin attribute to * to facilitate the external domain to call the CDN.

React also recommends that you validate the CDN’s request header properties to avoid cross-domain restrictions.

In other words, it is up to the other person (the responder header) to decide whether or not you can access a third-party resource. The other server can use your cookie referer and other request header parameters to determine the security of the request and decide whether to return the corresponding content. Note: The referer header cannot be modified by the pure front-end, otherwise an error will be reported.

->> Browsers divide requests into simple requests and complex requests

However, there is a detailed division of browser cross-domain restrictions, which is worth mentioning here: there are two types of requests: simple and complex. For simple requests, all of the following conditions (the “and” relationship) are met.

  1. The request method isGET.POST.HEADOne of the.
  2. The manually set request header does not exceed the following attributes:Accept.Accept-Language.Content-Language.
  3. Content-TypeThe attribute value istext/plain.multipart/form-data.application/x-www-form-urlencodedOne of the.
  4. Any of the requestsXMLHttpRequestUploadNone of the objects are registered with any event listeners;XMLHttpRequestUploadObjects can be usedXMLHttpRequest.uploadProperty access.
  5. Not used in the requestReadableStreamObject.

The first three are commonly used. If a request does not meet any of the above five conditions, it is a complex request.

Browsers distinguish between simple and complex requests in order to be compatible with forms, which have historically been able to make cross-domain requests.

->> How are XHR requests sent in the browser? How browsers handle simple and complex requests differently

Here I think Ruan yifeng’s article has been well written (link at the end of article), so if there are similarities (no, similarities)… Don’t think I’m copying, just using it legally under his Creative Commons 3.0 license.

  1. How browsers handle simple requests! If an XHR satisfies all the criteria for a simple request, it will be issued as follows:

    // Send an XHR request containing an Origin header directly to the server. For example: Origin: http://api.gold.xitu.io Origin means "Origin", contains protocol, domain name and port, and will tell the other party which source the request came from. If the source specified by Origin is not licensed (such as adding code to cnBlogs to Access Bilibili), the other party will return a response header that does not contain access-Control-Allow-Origin, and the browser will know that something has gone wrong and throw an error, Caught by the onError callback of XMLHttpRequest. Note: This error cannot be identified by the status code, because the status code for the HTTP response might be 200. Access-control-allow-origin: access-Control-allow-origin: access-Control-allow-origin: http://api.bbb.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: The fields above the FooBar that begin with access-Control - indicate the Access restrictions that the other server places on the request. Access-control-allow-origin: access-Control-allow-origin These can be urls, which limit the value of the Origin field on a request, or *, which accepts requests from any domain name, such as CDN code storage services. A Boolean value, which can only be true, indicating whether cookies are allowed. By default, cookies are not included in cross-domain requests. Access-control-expose-headers (optional): The getResponseHeader() method of the XHR object only gets six basic fields in a cross-domain request: Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma. If you want to get other fields, you must specify access-Control-expose-headers. The above example specifies that the getResponseHeader('FooBar') can return the value of the FooBar field. To send cookies to the server, specify the access-Control-allow-credentials field to true. On the other hand, the website owner must turn on the withCredentials attribute in the AJAX request. Var XHR = new XMLHttpRequest(); xhr.withCredentials = true; Otherwise, the browser won't send a Cookie, even if the server agrees to do so. In this case, even if the server asks for a Cookie, the browser does not process it. However, if the withCredentials setting is omitted, some browsers still send cookies together. In this case, you can explicitly disable withCredentials: xhr.withCredentials = false; Note that access-Control-allow-Origin cannot be set to an asterisk if cookies are to be sent, and must specify a specific domain name that corresponds to the requested web page. At the same time, cookies still follow the same origin policy, only the Cookie set with the server domain name will be uploaded, cookies of other domain names will not be uploaded, and the document. Cookie in the original web page code (cross-domain) can not read the Cookie under the domain name of the other server.Copy the code
  2. How browsers handle complex requests!

    The browser will first ask the server if the domain name of the current web page is on the server's license list, and which HTTP verb and header fields are available. The browser issues a formal XMLHttpRequest request only if it receives a positive response; otherwise, an error is reported. Here we go, this is a section of JS code! var url = 'http://api.aaa.com/cors'; var xhr = new XMLHttpRequest(); xhr.open('PUT', url, true); xhr.setRequestHeader('X-Custom-Header', 'value'); xhr.send(); As you can see, the PUT method is used, and the x-custom-header Header is artificially set, so this is a complex request. OPTIONS /cors HTTP/1.1 Origin: http://api.bbb.com access-Control-request-method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.aaa.com ... (and some more extraneous headers.) Precheck requests use the OPTIONS method to indicate that the request is being queried. In the request header, the key field is Origin, indicating which source the request came from. And Access - Control - Request - Method and Access - Control - Request - Headers can see what is, as soon as you see the Request Method and artificial set which attributes. After receiving the precheck request, the server determines whether the request header is OK, and if so, it can respond. The key information in the response header is as follows: access-control-allow-origin: http://api.bbb.com access-control-allow-methods: GET, POST, PUT access-Control-allow-headers: x-custom-header ~ 1. Access-control-allow-origin: Access-control-allow-methods (*) = access-control-allow-methods (*) 3. Access-control-allow-headers: specifies the request header parameter that can be set. Ok, so what if the server does not agree to the precheck request ~ returns a normal HTTP response, but without any CORS related header fields. At this point, the browser assumes that the server did not approve the precheck request. An error is therefore raised, which is caught by the onError callback function of the XMLHttpRequest object. The console will print the following error message: XMLHttpRequest cannot load http://api.aaa.com. Origin http://api.bbb.com is not allowed by Access-Control-Allow-Origin. Access-control-allow-methods: GET, POST, PUT // All supported access-Control-allow-headers: X-custom-header // If the browser Request includes the access-Control-request-headers field, the access-Control-allow-headers field is required and represents all supported Request Header fields. Access-control-allow-credentials (Optional): true // Cookie access-Control-max-age (optional): 1728000 // Indicates the validity period of the pre-check request, in seconds. For example, this request is valid for 20 days (1728,000 seconds), during which the request is not sent again.Copy the code

->> Case: Solve the cross-domain problem of a blog music player

The security limitations of browsers are not perfect, and it is possible to overcome the cross-domain limitations with some technical means if the front end does not involve complex operations such as captcha, login, and encryption. Cross-domain can be achieved without back-end support, but usually with the user’s knowledge. The idea is that you can make some cross-domain requests, but it’s up to the user to decide whether or not to get the content of the request. For example, if you want to add a music player to your blog, play THE content of QQ music. And as we all know, the Tencent side of the leech chain (can be understood as cross-domain) is very strong restrictions! Therefore, my general implementation is to cooperate with the back end, that is, to visit QQ music website, the music through the browser console Network bar to obtain the resource URL download and save to their own server. And then directly access their own server to obtain music resources (QQ music is generally M4A, netease is generally MP3, but by the way, netease has canceled the protection of piracy, so you can directly use netease server, but some music can not be played outside the domain with copyright protection). And if you want to pure front-end implementation of cross-domain music playback can use < IFrame >, Chrome parameter modification, Chrome plug-ins and other methods to achieve the chain.

These magical methods will be covered in detail in the next chapter.

Tag/ The big show is on! Nine solutions for overcoming cross-domain constraints

  1. Iframe tags can embed cross-domain content in your web pages, such as adding an iframe for a Bilibili video or Codepen Demo to your blog. But iframe has two drawbacks:

    1. Many servers simply refuse to cross domainsiframeThe request,
    2. Cross domain accessiframeThe content in the.

    Here are some pictures to get a feel for it:

    Cnblogs will be rejected if you insert iframe in ruan yifeng’s Blog.

    If the iframe is inserted into the site, there is no problem. It seems that the blog park has turned off cross-domain requests for security reasons.

    Bilibili is more open and can currently insert iframes.

    You can’t use iframe to read or tamper with Bilibili’s web page

    So this is ultimately just a way to “show content” to the user, with a lot of limitations, and if you want to read/tamper with content, you still have to be cognate

  2. Use the CORS method (Cross-domain resource sharing), which was introduced in chapter 1 and is very detailed. There is no need to repeat it.

    But this method is also subject to a variety of restrictions on the other server, can not do as one would like…

  3. Get a browser plugin to match (the ultimate big trick, directly ignore the cross-domain restrictions) hey hey hey! Surprise! Is there such a method? ! This is an amazing and powerful method that most articles on the web don’t think of, but it’s also very useful. If I were to do it, I would probably do it this way, cross-domains without back-end support! If your site is aimed primarily at geeks/explorative gamers, suggest your Chrome plugin or a script for oil monkey. For example, simply add a copy of your TemperMonkey script to copy&paste to make a cross-domain request. (The Oil Monkey /Chrome plugin is now very popular among geeks/developers, considering how many plugins you have installed… (Of course, one is not installed do not spray!

    But with all the Chrome plugins out there, you… Can you develop an extension on your own? I’m afraid it’s difficult… (In fact, if you know the front end, plug-in development is not difficult, as long as the understanding of Chrome plug-in specialized methods on the line. So here’s a quick overview of how to do it, and there’s plenty of documentation available online if you want to develop a fully functional plugin (it’s also covered in Chrome Developer)

    Why don’t you learn how others play it first. We opened a random folder of Chrome plugins developed by someone else (I opened Tempermonkey) and here’s what it looked like:

    There is a manifest.json file that is closely related to the fact that your plugin does not support cross-domain support, such as the oilmonkey’s:

    {
    "background": {
    "page": "background.html"
    },
    "browser_action": {
    "default_icon": {
    "16": "images/icon_grey16.png"."19": "images/icon_grey19.png"."24": "images/icon_grey24.png"."32": "images/icon_grey32.png"."38": "images/icon_grey38.png"
    },
    "default_popup": "action.html"."default_title": "Tampermonkey"
    },
    "commands": {
    "open-dashboard": {
    "description": "Open dashboard"
    },
    "open-dashboard-with-running-scripts": {
    "description": "Open dashboard with the current tab's URL used as filter"
    },
    "open-new-script": {
    "description": "Open new script tab"
    },
    "toggle-enable": {
    "description": "Toggle enable state"}},"content_scripts": [{"all_frames": true."js": [ "rea/common.js"."content.js"]."matches": [ "file:///*"."http://*/*"."https://*/*"]."run_at": "document_start"}]."content_security_policy": "script-src 'self'; object-src 'self';"."default_locale": "en"."description": "The world's most popular userscript manager"."differential_fingerprint": "1.2 ae827c5b75f9e167b3ed0bf65d0c330028dd0acf93a84a8f0f2d7e096024ba3"."icons": {
    "128": "images/icon128.png"."32": "images/icon.png"."48": "images/icon48.png"
    },
    "incognito": "split"."key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwuYtg7kY2YyNieOkV9pK/qcXwUXu0CFUO0zU6DLAGAJZK7zxrHlwg9a+zFH7CXqgH7zSfRce9KiYOHJa LPBXM66uPCliiQ6Q+bFaNZx1FxLXkZTFnlyPh8kkwwohLJeSQ9NQXqEfeTepDj5BRufAR48az0MC5aUTEj+fFXbzX7QIDAQAB"."manifest_version": 2."minimum_chrome_version": "64.0.0.0"."name": "Tampermonkey BETA"."offline_enabled": true."optional_permissions": [ "downloads"]."options_page": "options.html"."options_ui": {
    "chrome_style": false."open_in_tab": true."page": "options.html"
    },
    "permissions": [ "notifications"."unlimitedStorage"."tabs"."idle"."webNavigation"."webRequest"."webRequestBlocking"."storage"."contextMenus"."chrome://favicon/"."clipboardWrite"."cookies"."declarativeContent"."\u003Call_urls>"]."short_name": "TM BETA"."update_url": "https://clients2.google.com/service/update2/crx"."version": "4.14.6142"
    }
    Copy the code

    This is the soul of the Chrome plugin, set a variety of properties, including the Chrome plugin icon, click the Chrome plugin icon to open the popup page… There is only one cross-domain correlation here: the Permissions attribute.

    This property sets what permissions the plug-in has, such as which sites it can access at will.

    The oleaner monkey, for example, has a “\u003Call_urls>” in the permissions attribute. \u003C is the Unicode encoding of <, =

    , that is, the JS code defined by this plugin can access any website at will

    This is what the user sees:

    Achieve cross-domain documents about the Chrome plug-ins cooperate website, you can refer to this article wizardforcel gitbooks. IO/Chrome – doc /… That’s a pretty complete summary.

    When I searched for it, I was pleasantly surprised to find a plugin (I didn’t make it) called “Allow CORS”, which is very useful and is intended to help developers debug their sites across domains.

    User reviews are pretty good. The url is chrome.google.com/webstore/de… The purpose, of course, is the same as the name, which can remove cross-domain restrictions. So you can just ask users to install the plugin with one click and ignore the cross-domain restrictions. But Chrome because of Google reasons, there are restrictions in China, in the face of general users Chrome also supports upload local package to add plug-ins, is also very simple, download -> open developer mode -> drag add plug-ins OK!

    Ok, this method is real TQL.

  4. Cooperate with the client local proxy VPN(the ultimate big move) after reading the third method, I think the other should retire, after all, the third method should be the simplest. The fourth principle is similar, but the development is really troublesome ah. You want the user to install a system application, a local VPN, like Charles Fiddler. Request headers such as Referer and Origin are then automatically modified locally, pretending to be a normal user request. Not a good solution anyway.

  5. This article focuses on pure front-end development, I also do not understand the back-end (except basic PHP, used to build a blog to use) this method is also very practical, but not in detail. A resource is obtained through a normal request in a back-end language (such as Java) that does not involve a user’s cookie in the browser. Then go back to the front end and request a resource from the site (actually transferred from the other site).

    For example, the music player mentioned in chapter 1 is already being implemented on Github with a backend! And 1.9k stars! However, this analysis of downloaded music because of infringement, so in 2018 suspended maintenance, but down can still be used.

    ErrorHappensQwQ. Because only back-end search analysis, music resources are still from the other server (so QQ music chain protection is still effective, can not listen to ah… Netease is ok, after all, netease has always been open) want to know about, can pa point go in: github.com/maicong/mus…

  6. JSONP methods for script tag resources, browsers are not cross-domain restrictions! (Except when the other party does not return data according to the referer/ Origin attribute)

    For example, there is an implementation like this on the Internet:

    <! -- Native JS implementation -->
    <script type="text/javascript">
      window.jsonpCallback = function(res) {
        console.log(res);
      };
    </script>
    <script
      src="http://localhost:80/api/jsonp? &cb=jsonpCallback"
      type="text/javascript"
    ></script>
    <! JQuery Ajax implementation -->
    <script src="https://cdn.bootcss.com/jquery/3.5.0/jquery.min.js"></script>
    <script>
      $.ajax({
        url: "http://localhost:80/api/jsonp".dataType: "jsonp".type: "get".data: {
          msg: "hello"
        },
        jsonp: "cb".success: function(data) {
          console.log(data); }});</script>
    Copy the code

    Well, that’s how it works. It’s easy to get Script content, but only Script QWQ is supported…

  7. WebSocket implementation WebSocket is a feature of HTML5, which enables the browser to actively send content. It is suitable for live broadcast and other scenarios (such as byte Nuggets Live).

    WebSocket is useful (there is no cross-domain restriction of CORS), but there is no way to get the HTTP resource QAQ.

    So this method is not recommended!

  8. Window.postmessage () method This method can safely implement cross-source communication!

    Do not understand this method, you can go here to make up for the lesson ~ ->> developer.mozilla.org/zh-CN/docs/…

    This method is also introduced in HTML5CSS3 Authoritative Guide, but is seldom used in actual combat

    This method allows messaging between different interfaces: between multiple Windows, for example, and between a web page and its IFrame.

    QQ Music, for example, uses this method. If you open multiple play page, QQ Concert through this method between multiple interface communication, automatically pause the previous play page, avoid playing multiple music at the same time.

    Of course, because it can “safely” communicate across sources, this communication method also needs to be approved by the other server. So if you want to do not decent things (the other party does not allow the situation forced access to resources) also useless ah…

  9. Use the “allow cross-domain” method to open the browser since it is the browser’s restriction, can you turn this restriction off? Yes!

    Open it this way (Windows, XXX is your data directory):

    C:/... /... /path/chrome.exe --disable-web-security --user-data-dir=xxxxCopy the code

    Mac can do it too! Same thing.

    --disable-web-security --user-data-dir=~/Downloads/chrome-data
    Copy the code

    That’s it, but you have to reboot Chrome, which users may not want to do, so plugins are the best method I recommend.

Of course, there may be a legal warning if you improperly access third party content. Therefore, this article is just a cross-domain introduction and technical exploration and research, nothing more.

->> Details

Appendix – COMPARISON of CORS requests to JSONP

CORS serves the same purpose as JSONP, but is more powerful than JSONP.

JSONP supports only GET requests, and CORS supports all types of HTTP requests. JSONP has the advantage of supporting older browsers and being able to request data from sites that do not support CORS.

->> Reference link

MDN 英 文 版 developer.mozilla.org/zh-CN/docs/…

MDN English document developer.mozilla.org/en-US/docs/…

Nguyen other www.ruanyifeng.com/blog/2016/0…

The autumn wind notes segmentfault.com/a/119000002…

Think no precipitation segmentfault.com/a/119000001 – quiet DE…

Nuggets – Little Ming Ko juejin.cn/post/684490…

Nuggets – JackySummer juejin.cn/post/686155…

The Chrome Developers developer.chrome.com/docs/extens…

Html5Rocks www.html5rocks.com/en/tutorial…

Garden – small matches the blue ideal blog www.cnblogs.com/xiaohuochai…

Zhihu – Can a simple front-end solve cross-domain problems? www.zhihu.com/question/30…

Mdn-xhr introduction developer.mozilla.org/zh-CN/docs/…

Mdn-xhr developer.mozilla.org/zh-CN/docs/…

Mdn-access-control-allow-origin developer.mozilla.org/zh-CN/docs/…

Mdn-access-control-allow-origin developer.mozilla.org/en-US/docs/…

StackOverflow – How does Access-Control-Allow-Origin header work? Stackoverflow.com/questions/1…

StackOverflow – CORS with XMLHttpRequest not working stackoverflow.com/questions/2…

W3-cors Enabled www.w3.org/wiki/CORS_E…

->> Version History

Now available at V1.0 see Github(@Flightmakers)

V1.0 will be released in the afternoon of 2021.8.23

In the evening of August 23, 2021.Because the title was too complicated, it was changed and re-published.