• 解决跨域问题代码示例


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

    同源下可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

  • 相关阅读:
    mysql查找有某列但没有此列索引的表
    mysql找到所有索引
    mysq在某一刻同时获取主从库的位置点
    新书《深入应用C++11:代码优化与工程级应用》出版,感谢支持
    c++11实现一个简单的lexical_cast
    应该用bind+function取代虚函数吗?
    《深入应用C++11:代码优化与工程级应用》开始发售
    一个更好的C++序列化/反序列化库Kapok
    C++技术沙龙主要内容
    C++11模版元编程
  • 原文地址:https://www.cnblogs.com/twodog/p/12135221.html
Copyright © 2020-2023  润新知