Maison  >  Article  >  interface Web  >  Introduction détaillée à ajax cross-domain

Introduction détaillée à ajax cross-domain

angryTom
angryTomavant
2019-08-01 17:54:212499parcourir

Introduction détaillée à ajax cross-domain

AJAX cross-domain

Remarque : Une partie du contenu de cet article provient de MOOC.com. @MOOC.com : https://www.imooc.com

Introduction au cours

●Qu'est-ce que le problème inter-domaines AJAX

●Les raisons du cross-domaine AJAX problème

 QuantityPensées et méthodes pour résoudre les problèmes inter-domaines AJAX

Qu'est-ce que le problème inter-domaines AJAX

 QuantityEn termes simples, c'est lorsque le front-end appelle le interface de service back-end

●Si l'interface de service n'est pas dans le même domaine, des problèmes inter-domaines se produiront

Scénario inter-domaines AJAX

●Un modèle de développement de séparation front-end et back-end et développement orienté services

● Le développement front-end et back-end est indépendant, et le front-end doit appeler un grand nombre d'interfaces back-end

● Tant que l'interface back-end n'est pas dans le même domaine, des problèmes inter-domaines se produiront

● Les problèmes inter-domaines sont très courants et doivent être résolus. Problèmes inter-domaines sont également très importants

Raisons inter-domaines AJAX

Quantity Restrictions du navigateur : restrictions de vérification de la sécurité du navigateur

Quantity Inter-domaine (n'importe quel protocole, nom de domaine, port) Toute différence sera considéré comme cross-domain)

Quantity , de peu de valeur réelle

●XHR : N'utilisez pas XHR, utilisez JSONP, qui présente de nombreux inconvénients et ne peut pas répondre aux exigences de développement actuelles

● Inter-domaine : l'appelé est modifié pour prendre en charge les appels inter-domaines (spécifiez les paramètres) ; l'appelant modifie l'inter-domaine caché (en fonction du proxy)

Écrire le code de test

 Écriture de code back-end de l'appelé : Spring Boot

 légale Écriture de code front-end de l'appelant : Jquery

Pourquoi des problèmes inter-domaines surviennent-ils ?

L'image ci-dessus est également très claire, car le navigateur lui-même a des restrictions de sécurité (même origine).  Lorsque nous envoyons une requête XMLHttpRequest, si le domaine demandé (nom de domaine hôte, port) est différent, alors des problèmes inter-domaines surviendront (le client ne peut pas obtenir les données renvoyées par le serveur)

Il est à noter que des problèmes inter-domaines surviennent dans les requêtes XMLHttpRequest, c'est-à-dire qu'il n'y aura pas de problèmes inter-domaines s'il ne s'agit pas d'une requête XMLHttpRequest

●Un exemple très simple : Lorsque écrire une page Web, Introduction détaillée à ajax cross-domain, si l'URL n'est pas dans le domaine local, l'image peut toujours être obtenue normalement

Idées pour résolution de problèmes inter-domaines

Configuration de l'environnement

Introduction détaillée à ajax cross-domain2-1 Projet backend

Écriture de code

1. Créez un projet maven pom nommé ajax-server comme suit

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.myimooc</groupId>
    <artifactId>ajax-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>ajax-server</name>
    <description>Demo project for Spring Boot</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2 Écrivez la classe AjaxServerStart

package com.myimooc.ajax.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
 * <br>
 * 标题: 启动类<br>
 * 描述: AJAX跨域讲解后端项目<br>
 *
 * @author zc
 * @date 2018/04/18
 */
@SpringBootApplication
public class AjaxServerStart {
    public static void main(String[] args) {
        SpringApplication.run(AjaxServerStart.class, args);
    }
}

3. Écrivez une classe ResultBean

package com.myimooc.ajax.server.vo;
import java.io.Serializable;
/**
 * <br>
 * 标题: REST请求响应POJO类<br>
 * 描述: 封装请求响应结果<br>
 *
 * @author zc
 * @date 2018/04/18
 */
public class ResultBean implements Serializable{
    private static final long serialVersionUID = 7867107433319736719L;
    private String data;
    public ResultBean(String data) {
        this.data = data;
    }
    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
}

4. Écriture de la classe TestController

package com.myimooc.ajax.server.controller;
import com.myimooc.ajax.server.vo.ResultBean;
import com.myimooc.ajax.server.vo.User;
import org.springframework.web.bind.annotation.*;
/**
 * <br>
 * 标题: 测试控制器<br>
 * 描述: 提供REST服务<br>
 * 使用 @CrossOrigin 注解支持跨域,可以放到类或方法上面
 * @author zc
 * @date 2018/04/18
 */
@RestController
@RequestMapping("/test")
//@CrossOrigin
public class TestController {
    @GetMapping("/get1")
    public ResultBean get1() {
        System.out.println("TestController.get1");
        return new ResultBean("get1ok");
    }
    @PostMapping("/postJson")
    public ResultBean postJson(@RequestBody User user) {
        System.out.println("TestController.postJson");
        return new ResultBean("postJson" + user.getName());
    }
    @GetMapping("/getCookie")
    public ResultBean getCookie(@CookieValue(value = "cookie1") String cookie1) {
        System.out.println("TestController.getCookie");
        return new ResultBean("getCookie" + cookie1);
    }
    @GetMapping("/getHeader")
    public ResultBean getHeader(
            @RequestHeader("x-header1") String header1,
            @RequestHeader("x-header2") String header2) {
        System.out.println("TestController.getHeader");
        return new ResultBean("getHeader" + header1+header2);
    }
}

2-2 Projet frontal

Écriture de code

1. Créez un pom de projet maven nommé ajax-client comme suit

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.myimooc</groupId>
    <artifactId>ajax-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>ajax-client</name>
    <description>Demo project for Spring Boot</description>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jasmine</artifactId>
            <version>2.5.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2 Écrivez index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Index</title>
    <link rel="stylesheet" type="text/css" href="/webjars/jasmine/2.5.0/jasmine.css">
    <script src="/webjars/jquery/3.3.0/jquery.min.js"></script>
    <script src="/webjars/jasmine/2.5.0/jasmine.js"></script>
    <script src="/webjars/jasmine/2.5.0/jasmine-html.js"></script>
    <script src="/webjars/jasmine/2.5.0/boot.js"></script>
</head>
<body>
<a href="#" onclick="get1()">发生get1请求</a>
<script>
    function get1() {
        $.getJSON("http://localhost:8080/test/get1").then(
            function (res) {
                console.log(res);
            }
        )
    }
    // 每一个测试用例的超时时间
    jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
    // 请求的接口地址前缀
    var base = "http://localhost:8080/test";
    // 测试模块
    describe("AJAX讲解", function () {
        // 测试方法
        it("get1请求", function (done) {
            // 服务器返回的结果
            var result;
            $.getJSON(base + "/get1").then(
                function (res) {
                    result = res;
                }
            );
            // 由于是异步请求,需要使用setTimeout来校验
            setTimeout(function () {
                expect(result).toEqual({
                    "data":"get1ok"
                });
                // 校验完成,通知jasmine框架
                done();
            },100);
        });
        // // 测试方法
        // it("jsonp请求", function (done) {
        //     // 服务器返回的结果
        //     var result;
        //     $.ajax({
        //         url: base + "/get1",
        //         dataType: "jsonp",
        //         jsonp:"callback2",
        //         success: function (res) {
        //             result = res;
        //         }
        //     });
        //
        //     // 由于是异步请求,需要使用setTimeout来校验
        //     setTimeout(function () {
        //         expect(result).toEqual({
        //             "data":"get1ok"
        //         });
        //
        //         // 校验完成,通知jasmine框架
        //         done();
        //     },100);
        // });
        // 测试方法
        it("postJson请求", function (done) {
            // 服务器返回的结果
            var result;
            $.ajax({
                url:base+"/postJson",
                type:"POST",
                contentType:"application/json;charset=utf-8",
                data:JSON.stringify({name:"testName"}),
                success:function(res){
                    result = res;
                }
            });
            // 由于是异步请求,需要使用setTimeout来校验
            setTimeout(function () {
                expect(result).toEqual({
                    "data":"postJsontestName"
                });
                // 校验完成,通知jasmine框架
                done();
            },100);
        });
        it("getCookie请求", function (done) {
            // 服务器返回的结果
            var result;
            $.ajax({
                url:base+"/getCookie",
                xhrFields:{
                    // 发送 AJAX 请求时带上 cookie
                    withCredentials:true
                },
                success:function(res){
                    result = res;
                }
            });
            // 由于是异步请求,需要使用setTimeout来校验
            setTimeout(function () {
                expect(result).toEqual({
                    "data":"getCookietestName"
                });
                // 校验完成,通知jasmine框架
                done();
            },100);
        });
        it("getHeader请求", function (done) {
            // 服务器返回的结果
            var result;
            $.ajax({
                url:base+"/getHeader",
                headers:{
                    "x-header1":"AAA"
                },
                beforeSend:function(xhr){
                   xhr.setRequestHeader("x-header2","BBB")
                },
                success:function(res){
                    result = res;
                }
            });
            // 由于是异步请求,需要使用setTimeout来校验
            setTimeout(function () {
                expect(result).toEqual({
                    "data":"getHeaderAAABBB"
                });
                // 校验完成,通知jasmine框架
                done();
            },100);
        });
    });
</script>
</body>
</html>

3. Écrivez l'application .properties

server.port=8081

4 Écrivez la classe AjaxClientStart

package com.myimooc.ajax.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AjaxClientStart {
    public static void main(String[] args) {
        SpringApplication.run(AjaxClientStart.class, args);
    }
}

5. Démarrez AjaxServerStart et AjaxClientStart, et visitez http://localhost :8081, cliquez pour générer une requête get1, ce qui entraîne des problèmes inter-domaines comme suit

Résoudre les inter-domaines

3-1 Interdire la vérification

Paramètres inter-domaines du navigateur Chrome

lég

Méthode Windows

Document de référence : https://www.cnblogs.com/laden...

Mode d'emploi : Cible de saisie dans la page de propriétés Ajouter dans la case : --disable-web-security --user-data-dir=C:MyChromeDevUserData

QuantityMéthode Mac OS

Document de référence :

http://blog.csdn.net/justinji...

  使用说明:用命令行打开 Google Chrome:open -a "Google Chrome" --args --disable-web-security

3-2 使用JSONP

代码编写

1.编写JsonpAdvice类

package com.myimooc.ajax.server.controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;
/**
 * <br>
 * 标题: JSONP 全局处理<br>
 * 描述: 统一处理JSONP<br>
 *
 * @author zc
 * @date 2018/04/18
 */
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice{
    public JsonpAdvice() {
        // 与前端约定好回调方法名称,默认是callback
        super("callback2");
    }
}

2.修改index.html

// 测试方法
        it("jsonp请求", function (done) {
            // 服务器返回的结果
            var result;
            $.ajax({
                url: base + "/get1",
                dataType: "jsonp",
                jsonp:"callback2",
                success: function (res) {
                    result = res;
                }
            });
            // 由于是异步请求,需要使用setTimeout来校验
            setTimeout(function () {
                expect(result).toEqual({
                    "data":"get1ok"
                });

                // 校验完成,通知jasmine框架
                done();
            },100);
        });

JSONP的弊端

服务器需要改动代码支持只支持GET发送的不是XHR请求

3-3 支持跨域

常见的JavaEE架构

跨域解决方向

  ●被调用方解决

  ●基于支持跨域的解决思路

  ●基于Http协议关于跨域的相关规定,在响应头里增加指定的字段告诉浏览器,允许调用

  ●跨域请求是直接从浏览器发送到被调用方

  ●修改被调用方的Http服务器

调用方解决

  ●基于隐藏跨域的解决思路

  ●跨域请求不会浏览器直接发送到被调用方

  ●而是从中间的Http服务器(Apache、Nginx)转发过去

  ●修改调用方的Http服务器

被调用方支持跨域

  ●【重点】Web应用服务器(Tomcat、Netty、WebLogic或应用程序)实现

  ●Http服务器(Nginx)配置实现

  ●Http服务器(Apache)配置实现

使用Filter解决

编写代码

1.编写CrosFilter类

package com.myimooc.ajax.server.config;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * <br>
 * 标题: 服务端解决跨域<br>
 * 描述: 使用Filter<br>
 *
 * @author zc
 * @date 2018/04/18
 */
public class CrosFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse)response;
        HttpServletRequest req = (HttpServletRequest)request;
        // 支持所有域
        String origin = req.getHeader("Origin");
        if (!StringUtils.isEmpty(origin)){
            // 支持任何域名的跨域调用 且 支持带cookie(是被调用方域名的cookie,而不是调用方的cookie)
            res.addHeader("Access-Control-Allow-Origin",origin);
        }
        // 指定允许的域,带cookie时,origin必须是全匹配,不能使用 *
//        res.addHeader("Access-Control-Allow-Origin","http://localhost:8081");
        // 允许所有域,但不能满足带 cookie 的跨域请求
//        res.addHeader("Access-Control-Allow-Origin","*");
        // 支持所有自定义头
        String headers = req.getHeader("Access-Control-Allow-Headers");
        if (!StringUtils.isEmpty(headers)){
            // 允许所有header
            res.addHeader("Access-Control-Allow-Headers",headers);
        }
        // 允许所有header
//        res.addHeader("Access-Control-Allow-Headers","*");
        // 指定允许的方法
//        res.addHeader("Access-Control-Allow-Methods","GET");
        // 允许所有方法
        res.addHeader("Access-Control-Allow-Methods","*");
        // 允许浏览器在一个小时内,缓存跨域访问信息(即上面三个信息)
        res.addHeader("Access-Control-Max-Age","3600");
        // 启用 cookie
        res.addHeader("Access-Control-Allow-Credentials","true");
        chain.doFilter(request,response);
    }
    @Override
    public void destroy() {
    }
}

2.编写FilterConfig类

package com.myimooc.ajax.server.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * <br>
 * 标题: 配置类<br>
 * 描述: 注册CrosFilter<br>
 *
 * @author zc
 * @date 2018/04/18
 */
@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean registrationBean(){
        FilterRegistrationBean filter = new FilterRegistrationBean();
        filter.addUrlPatterns("/*");
        filter.setFilter(new CrosFilter());
        return filter;
    }
}

3.启动AjaxServerStart和AjaxClientStart,并访问http://localhost:8081,跨域解决

简单请求与非简单请求

  ●简单请求:浏览器先发送真正的请求后检查

  ●请求方法:GET、HEAD、POST的一种

  ●请求header:无自定义header;Content-Type为:text/plain、multipart/form-data、application/x-www-form-urlencoded的一种

  ●非简单请求:浏览器先发预检命令,检查通过后,才发送真正的请求

  ●常见的有:PUT、DELETE

  ●其它条件:发送Json格式的请求、带自定义header的请求

  ●预检命令:浏览器检测到跨域请求, 会自动发出一个OPTIONS请求, 就是所谓的预检(preflight)请求。当预检请求通过的时候,才发送真正的请求。

Nginx配置

  ●修改主机hosts文件增加映射本地域名:127.0.0.1 b.com(表示被调用方的域名)

  ●在conf目录下创建vhost目录

  ●修改nginx.conf在最后面增加一行代码:include vhost/*.conf;

  ●在vhost目录下创建b.com.conf

  ●启动niginx,访问b.com/test/get1

编写b.com.conf

server{
    listen 80;
    server_name b.com;
    location /{
        proxy_pass http://localhost:8080/;
        add_header Access-Control-Allow-Methods *;
        add_header Access-Control-Max-Age 3600;
        add_header Access-Control-Allow-Credentials true;
        add_header Access-Control-Allow-Origin $http_origin;
        add_header Access-Control-Allow-Headers $http_access_control_allow_headers;
        if ($request_method = OPTIONS){
            return 200;
        }
    }
}

Apache配置

  ●修改conf/httpd.conf找到LoadModule vhost_alias_module module/mod_vhost_alias.so取消注释

  ●修改conf/httpd.conf找到LoadModule proxy_module module/mod_ proxy.so取消注释

  ●修改conf/httpd.conf找到LoadModule proxy_http_module module/mod_ proxy_http.so取消注释

  ●修改conf/httpd.conf找到LoadModule headers_module module/mod_ headers.so取消注释

  ●修改conf/httpd.conf找到LoadModule rewrite_module module/mod_ rewrite.so取消注释

  ●修改conf/httpd.conf找到Include conf/extra/httpd-vhosts.conf取消注释

  ●修改conf/extra/httpd-vhosts.conf在最后面增加下面的内容即可

<VirtualHost *:80>
    ServerName b.com
    ErrorLog "logs/b.com-error.log"
    CustomLog "logs/b.com-access.log" common
    ProxyPass / http://localhost:8080/
    # 把请求头的origin值返回到Access-Control-Allow-Origin字段
    Header always set Access-Control-Allow-Origin "expr=%{req:origin}"
    # 把请求头的Access-Control-Allow-Headers值返回到Access-Control-Allow-Headers字段
    Header always Access-Control-Allow-Headers "expr=%{Access-Control-Allow-Headers}"
    Header always set Access-Control-Allow-Methods "*";
    Header always set Access-Control-Max-Age "3600";
    Header always set Access-Control-Allow-Credentials ""true";
    # 处理预检命令OPTIONS,直接返回204
    RewriteEngine On
    RewriteCond %{REQUEST_METHOD}OPTIONS
    RewriteRule ^(.*)$"/" [R=204,L]
</VirtualHost>

Spring框架支持

在类或方法上使用注解@CrossOrigin即可支持跨域

3-4 隐藏跨域

  ●使用Nginx反向代理实现

  ●修改主机hosts文件增加映射本地域名:127.0.0.1 a.com

  ●在vhost目录下创建a.com.conf

  ●启动niginx,访问a.com/ajaxserver/get1

编写a.com.conf

server{
    listen 80;
    server_name a.com;
    location /{
         proxy_pass http://localhost:8081/;
    }
    location /ajaxserver{
         proxy_pass http://localhost:8080/test/;
    }
}

使用Apache反向代理实现

修改conf/extra/httpd-vhosts.conf在最后面增加下面的内容即可

<VirtualHost *:80>
    ServerName a.com
    ErrorLog "logs/a.com-error.log"
    CustomLog "logs/a.com-access.log" common
    ProxyPass / http://localhost:8081/
    ProxyPass /ajaxserverapache http://localhost:8080/test
</VirtualHost>

课程总结

4-1 课程总结

课程总结

  ●产生原因:主要是浏览器对Ajax请求的限制

  ●解决思路:JSONP、支持跨域、隐藏跨域

  ●核心原理:了解Http协议关于跨域方面的规定

 QuantitySolution : Utiliser le filtre, les proxys directs et inverses Nginx, les proxys directs et inverses Apache, la prise en charge du framework Spring

Introduction détaillée à ajax cross-domain

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer