vue、springboot集成websocket跨域问题解决 - Go语言中文社区

vue、springboot集成websocket跨域问题解决


       由于浏览器连接的是服务器上的websocket,导致出现了如下跨域错误:

The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://a.com' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute。

     先分析下出现这个问题的原因:由于前后端分离导致我们通常会写跨域配置(如下代码)。但是报错很明显指出request's credentials mode is 'include',那么响应就the response must not be the wildcard '*’。所以直接配置Access-Control-Allow-Origin的值为通配是行不通的。具体怎么解决我接下来会讲。

package cn.datainvest.core.config;

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 yangfeng
 *
 */
@Configuration
public class CorsConfig {

    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        return corsConfiguration;
    }

    /**
     * 跨域过滤器
     *
     * @return
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }
}

springboot集成websocket步骤如下:

1.引入依赖

        <!--Websocket-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

2:WebSocketConfig

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

/**
 * @author yangfeng
 **/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket").setAllowedOrigins("*").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");
    }
}

3.业务代码

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;


@Component
public class Weather {

    @Resource
    private IWeatherService weatherService;

    private static Logger LOG = LoggerFactory.getLogger(WeatherScheduler.class);

    @Autowired
    private SimpMessagingTemplate messagingTemplate;


    /**
     * 保存天气信息
     */
    public void saveWeather() {
        ServiceResult<WeatherAO> serviceResult = weatherService.getWeatherAndSave();
        if (serviceResult != null && serviceResult.isSucceed() && serviceResult.getData() != null) {
            WeatherAO weather = serviceResult.getData();
            //发送数据到webscoket
            messagingTemplate.convertAndSend("/topic/weather", weather);
        }
    }

}

4.vue连接socket,开发环境访问地址:localhost:8089。很明显连接这里出现跨域了。

<template>
  <div class="">、
    <h1>Stock Price</h1>
    <div>
      <button @click="senMessage">发送消息</button>
      <ul>
        <li v-for="m in list1" :key="m.name">{{ m.name }}: {{ m.price }}</li>
      </ul>
    </div>
  </div>
</template>

<script>
  import SockJS from 'sockjs-client'
  import Stomp from 'webstomp-client'
  export default {
    data() {
      return {
        list1: [],
        stompClient: null

      }
    },
    mounted() {
      this.initWebSocket()
    },
    methods: {
      senMessage() {
        this.stompClient.send('/app/hello')
      },
      initWebSocket() {
        this.connection()
        // 需要有一个失败重连得到问题
      },
      connection() {
        // 更换that指针
        const socket = new SockJS('http://112.174.126.131:8080/websocket')
        this.stompClient = Stomp.over(socket)
//建立连接,订阅主题
        this.stompClient.connect({}, (frame) => {
          console.log(frame)
          this.stompClient.subscribe('/topic/terminalTrace', (val) => {
            // this.list1 = JSON.parse(val.body)
            console.log('-------++++++++++++++++++++++++++++++------------')
//下面会报错,应该是json的问题,但是数据可以接收到
            console.log(val.body)
          })
          this.stompClient.subscribe('/topic/weather', (val) => {
            // this.list1 = JSON.parse(val.body)
            console.log('-------++++++++++++++++++++++++++++++------------')
//下面会报错,应该是json的问题,但是数据可以接收到
            console.log(val.body)
          })
        })
        // 回调函数 3 end
      }
    }
  }
</script>

5.使用filter来解决

   把之前写的跨域类CorsConfig 删除,加入下面的filter。

import org.springframework.stereotype.Component;

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

@Component
public class CorsFilter implements Filter {

    // This is to be replaced with a list of domains allowed to access the server
    //You can include more than one origin here
    private final List<String> allowedOrigins = Arrays.asList("http://localhost:8089");

    public void destroy() {

    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        // Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects)
        if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;

            // Access-Control-Allow-Origin
            String origin = request.getHeader("Origin");
            response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "*");
            response.setHeader("Vary", "Origin");

            // Access-Control-Max-Age
            response.setHeader("Access-Control-Max-Age", "3600");

            // Access-Control-Allow-Credentials
            response.setHeader("Access-Control-Allow-Credentials", "true");

            // Access-Control-Allow-Methods
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");

            // Access-Control-Allow-Headers
            response.setHeader("Access-Control-Allow-Headers",
                    "Origin, X-Requested-With, Content-Type, Accept, " + "X-CSRF-TOKEN");
        }

        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {
    }
}

加入origin的路径配置: 

6.测试

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/xiaoxiangzi520/article/details/106628992
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-06-28 02:02:46
  • 阅读 ( 824 )
  • 分类:前端

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢