前后端分离下的跨域问题

问题产生的原因

  前后端分离项目中,前端和后台服务可能没有部署在一台服务器上。这样的话,前后端ip就会不一致,那么就会产生跨域,往往前后端项目部署的端口通常也可能会不一样,这样也会产生跨域问题。再就是使用的域名不一致也会产生这样的问题。

错误信息

Failed to load http://192.168.2.111:8080/login: No ‘Access-Control-Allow-Origin‘ header ispresent on the requested resource. Origin ‘http://192.168.2.110:8084‘ is therefore not allowed access. The response had HTTP status code 405.

反正差不多就是上面这样的报错。

前端实现

前端可以使用jsonp的方式解决这个问题,但只能针对get方法。

Node也有开源的组件http-proxy-middleware可以支持代理。

var express=require(‘express‘);
var proxy=require(‘http-proxy-middleware‘);
var app=express();
app.use(‘/api‘,proxy({target:‘http://192.168.2.110:8080‘, changeOrigin:true}));
app.listen(3000);

Nginx实现

设置反向代理

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  ‘$remote_addr - $remote_user [$time_local] "$request" ‘
    #                  ‘$status $body_bytes_sent "$http_referer" ‘
    #                  ‘"$http_user_agent" "$http_x_forwarded_for"‘;

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    upstream appstore-web {
        server 192.168.2.110:8080;
    }

    server {
        listen       80;
        server_name  192.168.2.111;
        client_max_body_size    1000M;
        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root    /jyzh/appstore-front/dist;
            index    index.html;
        }

        location /appstore-web {
            proxy_pass http://appstore-web;
            proxy_set_header  Host  $host;
            proxy_set_header  X-Real-IP  $remote_addr;
            proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;
        }
    }

    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

后端实现

过滤器

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 全局跨域过滤器
 *
 * @author wzm
 * @version 1.0.0
 * @date 2020/1/25
 **/
public class CrosFilter implements Filter {

    public static final Logger LOGGER = LoggerFactory.getLogger(CrosFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) servletResponse;

        HttpServletRequest req = (HttpServletRequest)servletRequest;
        LOGGER.info("****执行跨域拦截****",req.getRequestURI());

        //*号表示对所有请求都允许跨域访问
        res.addHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,Authorization");
        res.addHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,PATCH,OPTIONS");
        res.setHeader("Access-Control-Max-Age", "3600");

        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

springboot配置

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * 全局跨域
 *
 * @author wzm
 * @version 1.0.0
 * @date 2020/1/25
 **/
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "DELETE", "PATCH")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

终极解决办法(CORS)

  简单来说,CORS是一种访问机制,英文全称是Cross-Origin Resource Sharing,即我们常说的跨域资源共享,通过在服务器端设置响应头,把发起跨域的原始域名添加到Access-Control-Allow-Origin 即可。

  这种方式几乎适用于所有场景。



Request Headers(请求头)

Origin

  表示跨域请求的原始域。

Access-Control-Request-Method

  表示跨域请求的方式。(如GET/POST)

Access-Control-Request-Headers

  表示跨域请求的请求头信息。



Response headers(响应头 )

Access-Control-Allow-Origin

  表示允许哪些原始域进行跨域访问。(字符数组)

Access-Control-Allow-Credentials

  表示是否允许客户端获取用户凭据。(布尔类型)

从浏览器发起跨域请求,并且要附带Cookie信息给服务器。则必须具备两个条件:

1. 浏览器端:发送AJAX请求前需设置通信对象XHR的withCredentials 属性为true。

2. 服务器端:设置Access-Control-Allow-Credentials为true。两个条件缺一不可,否则即使服务器同意发送Cookie,浏览器也无法获取。

Access-Control-Allow-Methods

  表示跨域请求的方式的允许范围。(例如只授权GET/POST)

Access-Control-Allow-Headers

  表示跨域请求的头部的允许范围。

Access-Control-Expose-Headers

  表示暴露哪些头部信息,并提供给客户端。(因为基于安全考虑,如果没有设置额外的暴露,跨域的通信对象XMLHttpRequest只能获取标准的头部信息)

Access-Control-Max-Age

  表示预检请求 [Preflight Request] 的最大缓存时间。


CorsFilter

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * 全局跨域
 *
 * @author wzm
 * @version 1.0.0
 * @date 2020/1/25
 **/
@Configuration
public class GlobalCorsConfig {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        //放行哪些原始域
        config.addAllowedOrigin("*");
        //是否发送Cookie信息
        config.setAllowCredentials(true);
        //放行哪些原始域(请求方式)
        config.addAllowedMethod("*");
        //放行哪些原始域(头部信息)
        config.addAllowedHeader("*");
        //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
        config.addExposedHeader("*");

        //添加映射路径
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);

        //返回新的CorsFilter
        return new CorsFilter(configSource);
    }
}

WebMvcConfigurer

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 全局跨域
 *
 * @author wzm
 * @version 1.0.0
 * @date 2020/1/25
 **/
@Configuration
public class GlobalCorsConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            //重写父类提供的跨域请求处理的接口
            public void addCorsMappings(CorsRegistry registry) {
               //添加映射路径
                registry.addMapping("/**")
                      //放行哪些原始域
                        .allowedOrigins("*")
                      //是否发送Cookie信息
                        .allowCredentials(true)
                      //放行哪些原始域(请求方式)
                        .allowedMethods("GET","POST", "PUT", "DELETE")
                      //放行哪些原始域(头部信息)
                        .allowedHeaders("*")
                      //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
                        .exposedHeaders("Token", "Channel");
            }
        };
    }
}

CrossOrigin注解

1、在方法上(@RequestMapping)使用注解 @CrossOrigin

@RequestMapping("/hello")
@ResponseBody
@CrossOrigin("http://192.168.2.110:8080")
public String hello( ){
    return "hello";
}

2、在控制器(@Controller)上使用注解 @CrossOrigin

@Controller
@CrossOrigin(origins = "http://192.168.2.110:8080", maxAge = 3600)
public class HelloController{
    @RequestMapping("/hello")
    @ResponseBody
    public String hello( ){
        return "hello";
    }
}

原文地址:https://www.cnblogs.com/jockming/p/12233215.html

时间: 2024-10-29 02:30:50

前后端分离下的跨域问题的相关文章

前后端分离,解决跨域问题及django的csrf跨站请求保护

1. 前后端分离解决跨域问题 解决跨域调用服务并设置headers 主要的解决方法需要通过服务器端设置响应头.正确响应options请求,正确设置 JavaScript端需要设置的headers信息 方能实现: 关于跨域,前端会先发送OPTIONS请求,进行预检,检查后端是否允许前端设置的相应的请求头,请求内容 function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie

springboot shiro 前后端分离,解决跨域、过虑options请求、shiro管理session问题、模拟跨域请求

一.解决跨域.过虑options请求问题 1.创建过虑类 import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; im

前后端分离开发与跨域问题

前后端分离 传统开发方式 曾几何时,JSP和Servlet为Java带来了无限风光,一时间大红大紫,但随着互联网的不断发展,这样的开发方式逐渐显露其弊端,在移动互联网炙手可热的今天,应用程序对于后台服务的要求发生了巨大的变化; 传统的项目开发与交互流程: 在传统的web开发中,页面展示的内容以及页面之间的跳转逻辑,全都由后台来控制,这导致了前后端耦合度非常高,耦合度高则意味着,扩展性差,维护性差,等等问题 传统开发的问题如下: 耦合度高 调试麻烦,出现问题时往往需要前后台一起检查 开发效率低,前

Vue + SpringBoot + nginx:(1)开发环境npm run dev下,通过nginx解决前后端分离造成的跨域问题

前面看了很多的博客,在使用nginx进行反向代理的时候,都是讲通过 build 后...但是,我只是希望在 npm run dev 的时候进行 nginx 的反向代理,因为我只是在开发环境啊!!! build 个锤子... 前提:后端环境已经搭建完成.前端页面可通过npm进行启动.下载好nginx 前端页面接口:8081(这个端口可以通过配置文件自定义) 服务端接口:8902 nginx 包 大体思路: 1.nginx 上配置好监听的端口号(这样前端页面访问端口就能被检测到).代理到服务端的地址

解决vue+springboot前后端分离项目,前端跨域访问sessionID不一致导致的session为null问题

问题: 前端跨域访问后端接口, 在浏览器的安全策略下默认是不携带cookie的, 所以每次请求都开启了一次新的会话. 在后台打印sessionID我们会发现, 每次请求的sessionID都是不同的, 既然每次请求都是一个新的会话, 那我们去获取session的时候自然就是null了. 解决办法如下: 环境: vue 2.0 springboot 2.1.6 一.前端部分 1.  在vue引入axios的位置添加以下代码 import axios from 'axios' axios.defau

前后端分离Django解决跨域的问题

现在,前端与后端分处不同的域名,我们需要为后端添加跨域访问的支持 否则前端无法使用axios无法请求后端提供的api数据,我们使用CORS来解决后端对跨域访问的支持. 使用django-cors-headers扩展 在 Response(headers={"Access-Control-Allow-Origin":'客户端地址/*'}) 文档:https://github.com/ottoyiu/django-cors-headers/ 安装 pip install django-co

前后端分离ajax请求跨域问题

解决方案一(服务器端): 1.java语言 如果您使用的mvc框架是spring4.2以上的话,一个@CrossOrigin就可以搞定.将@CrossOrigin加到Controller上,那么这个Controller所有的请求都是支持跨域的,代码如下: @Controller @CrossOrigin public class GreetingController {} 将@CrossOrigin加到请求方法上,那么这个请求是支持跨域的,代码如下 @CrossOrigin @RequestMa

前后端分离下spring security 跨域问题等

最近在做一个项目,前后端分离,不可避免的遇到了跨域问题.起初是配置跨域: @Configurationpublic class CorsConfig extends WebMvcConfigurerAdapter { private CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("

关于大型网站技术演进的思考(十六)--网站静态化处理—前后端分离—下(8)

我第一次听说nodejs技术大概是在2009年年末,不过我真正认真在网络上进一步了解nodejs还是在2010年年中,当时对nodejs的认识和我现在对nodejs的认识有着天壤的区别,开始想了解nodejs我只是为了感慨谷歌公司开发的V8引擎居然如此强大,它不仅仅可以作为chrome浏览器的javascript内核运行平台,居然还能为服务端使用javascript语言作为平台,通过对nodejs的了解让我认识到chrome浏览器是如此的优秀,但是如此相对的是我并不认为javascript作为服