zoukankan      html  css  js  c++  java
  • 解决跨域问题代码示例

    本篇提供几个例子,从代码层面说明同源政策何时起作用,并尝试通过几种不同的方法解决跨域问题。

    同源下可Ajax成功

    先是第一版,一个简单的flask程序。自己请求自己,不会有什么问题。 打开浏览器输入:http://127.0.0.1:4000 会返回字符串回去,交给浏览器,其解析运行其中的javascript代码,发出ajax请求,至同服务下的/get_data路由,得到数据后渲染至页面。 代码如下:

    # -*- coding: utf-8 -*-
    from flask import Flask
    app = Flask(__name__)
    
    
    content = '''
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <script>
    var xhr = new XMLHttpRequest();
    
    // 指定通信过程中状态改变时的回调函数
    xhr.onreadystatechange = function(){
      // 通信成功时,状态值为4
      if (xhr.readyState === 4){
        if (xhr.status === 200){
            document.body.innerHTML = xhr.responseText
        } else {
            document.body.innerHTML = xhr.statusText
        }
      }
    };
    
    xhr.onerror = function (e) {
      console.error(xhr.statusText);
    };
    
    // open方式用于指定HTTP动词、请求的网址、是否异步
    xhr.open('GET', 'http://127.0.0.1:4000/get_data', true);
    
    // 发送HTTP请求
    xhr.send(null);
    </script>
    </body>
    </html>
    '''
    
    
    @app.route("/")
    def hello():
        return content
    
    
    @app.route('/get_data')
    def get_data():
        return 'got data!'
    
    
    if __name__ == '__main__':
        app.run(port=4000)
    复制代码

    结果为:

    此处需要注意的是,若127.0.0.1换成localhost则该请求会被同源政策禁止。

    不同源时Ajax不成功

    此时,我们再启一个flask项目,端口定在5000,修改上面代码中xhr open的地址,使4000端口的ajax去5000取数据。

    # -*- coding: utf-8 -*-
    from flask import Flask
    app = Flask(__name__)
    
    @app.route("/get_data_5000")
    def hello():
        return "got data in 5000!"
    
    
    if __name__ == '__main__':
        app.run(port=5000)
    复制代码

    得到如下结果:

    显然,由于端口号已经不一致,违反了同源政策,请求失败。

    使用应用层第三方包

    在应用层,使用第三方包增加http response header的方式来处理。 5000项目变为:

    # -*- coding: utf-8 -*-
    from flask import Flask
    from flask_cors import CORS
    app = Flask(__name__)
    CORS(app)
    复制代码

    重启项目后,访问http://127.0.0.1:4000即可拿到5000的数据。

    可以看到第三方包自动处理了response header。

    此处不只是flask,不只是python,各个语言,各种web框架,都可以在这一层通过第三方包的形式来处理跨域问题,如果找不到相关插件,大不了自己写一个好喽。

    代理屏蔽

    此时要Nginx上场了。 思路是,启项目于4000和5000端口,浏览器不直接通过端口访问web服务,而是通过Nginx的80端口,Nginx将实际上有两个项目这件事情对浏览器屏蔽掉。 改Nginx配置为:

    server {
           listen       80;
           server_name  localhost;
    
           location / {
               proxy_pass http://127.0.0.1:4000;
           }
    
           location /get_data_5000 {
               proxy_pass http://127.0.0.1:5000/get_data_5000;
           }
       }
    复制代码

    然后去掉flask-cors插件,再将4000中的ajax url改为http://127.0.0.1/get_data_5000

    效果如图:

    可以看到,此时不再需要response header中的Access-Control-Allow-Origin即可请求到另一个项目的服务。

    这种处理方法可以联想到设计模式中的facade模式,此时Nginx即为外观层,后面到底有多少个项目在提供服务,请求者不需要关心。

    不过这种方式是有一定局限性的,即只有这个Nginx可导向的服务才可不受跨域问题影响。

    Nginx配置Header

    移除之前的Nginx配置,通过4000端口访问页面,将5000端口的项目通过Nginx访问,并在Nginx这一层,来处理response header。

    这里抄一下配置。

    location /get_data_5000 {
        proxy_pass http://127.0.0.1:5000/get_data_5000;
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            #
            # Custom headers and headers various browsers *should* be OK with but aren't
            #
            add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            #
            # Tell client that this pre-flight info is valid for 20 days
            #
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }
        if ($request_method = 'POST') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        }
        if ($request_method = 'GET') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        }
       }
    复制代码

    配置中可写if,可按需要操作header,结果如下:

    OK, Well done!

    转载于:https://juejin.im/post/5c517ed6e51d45517411c736

  • 相关阅读:
    关于同余最短路
    【水】关于 __attribute__
    题解【AtCoder
    一些简单图论问题
    浅谈简单动态规划
    关于博客园主题(美化博客园)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第47章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第46章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第45章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第44章 读书笔记(待更新)
  • 原文地址:https://www.cnblogs.com/twodog/p/12135222.html
Copyright © 2011-2022 走看看