跨域问题的三种解决方案

概述

当前端页面与后台运行在不同的服务器时,就必定会出现跨域这一问题,本篇简单介绍解决跨域的三种方案,部分代码截图如下,仅供参考:

Nginx代理

这种方式比较简单,将A应用和B应用都通过一个统一的地址进行转发,这样就可以避免跨域问题出现。


server {
        listen       80;
        server_name  www.gameloft9.top;
 
        #charset koi8-r;
 
        #access_log  logs/host.access.log  main;
 
        location / {
            root   html;
            index  index.html index.htm;
        }
location /manager {
            proxy_pass http://127.0.0.1:6108/manager;
            proxy_set_header Host $http_host;
        }
location /service {
            proxy_pass http://127.0.0.1:9200/service;
            proxy_set_header Host $http_host;
        }
 
        #error_page  404              /404.html;
 
        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
		}

在上面的配置中,manager和service属于不同的域(IP虽然一样,但是端口不一样),如果manger里面的js调用service里面的接口,会报跨域错误。通过nginx转发后,所有的域都映射到www.gameloft9.top了,然后通过/manager,/service分别转发到各自的应用中,巧妙的避免了跨域问题。如果是纯前端项目,可以直接托管到nginx里面,也可以解决跨域问题,原理一样。

JSONP

因为< script>标签不受跨域限制,因此在此基础上出现了JSONP的ajax请求方式。通过包装一个< script>标签,去请求接口,然后返回数据及回调函数,这样就达到了跨域的目的。

/**
     * 测试JSONP跨域请求
     * */
    function testJsonP() {
        $.ajax({
            url: root + "/testjsonp.do",
            type: "GET",//jsonp只支持GET请求
            data: request,
            dataType: "jsonp",
            jsonp: "callback",//指定查询字符串中回调方法key
            jsonpCallback: "print",//指定查询字符串中回调方法value,例如callback=print
            success: function (data) {//返回的是回调方法的入参
                //alert(data)
            }
        })
    }

JSONP的请求方式,需要设置dataType为"jsonp",表明这是一个jsonp的请求,jsonp是指定查询字符串中回调函数的参数的名称,jsonpCallback指定的是查询字符串中回调的函数名。一个标准的jsonp的请求如下所示:

http://localhost:8080/demo/testjsonp.docallback=print&number=2&_=1519870989148

jsonp只支持get请求,所有的参数都会转化为查询字符串,然后再补上回调函数的参数(就是这里的callback=print),如果jsonpCallback没有指定,jQuery会自动生成一个随机的函数名称,例如:

Query17208297070672462461_1491991295320

当然我们不建议这么做。

后台处理如下:

/**
     * 测试ajax josnp跨域请求
     * */
    @RequestMapping(value = "/testjsonp.do", method = RequestMethod.GET)
    //@ResponseBody
    public void test(Model model,String callback,String number, HttpServletRequest request,HttpServletResponse response)throws Exception{
        //如果是spring mvc,启用了@ResponseBody注解,可以直接返回调用语句
        //return callback+"("+result.toString()+")";
 
        Integer result = Integer.parseInt(number);
        result = result*result;//计算平方值
 
        Writer client = response.getWriter();
        client.write(callback+"("+result.toString()+")");
        client.flush();
    }

后台接受到参数后,进行业务逻辑调用,并把结果塞进回调函数中,返回即可。

设置Access-Control-Allow-*头

jsonp的方式虽然简便,但有个缺点,就是只支持get请求,对于只支持post的接口就不支持了。通过后台设置Access-Control-*等header,可以解决跨域问题,而且get,post都支持。

/**
     * 测试ajax 设置head跨域请求
     * */
    @RequestMapping(value = "/testCrossOrigin.do", method = RequestMethod.POST)
    @ResponseBody
    public String crossOrigin(Model model,String number,HttpServletRequest request,HttpServletResponse response)throws Exception{
 
        //设置response header,允许跨域请求
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("Access-Control-Allow-Methods","POST");
        response.setHeader("Access-Control-Allow-Headers","x-requested-with,content-type");
        response.setHeader("Access-Control-Allow-Max-Age","1728000");//单位:秒,这里是20天
 
        Integer result = Integer.parseInt(number);
        result = result*result;
 
       return result.toString();
    }

Access-Control-Allow-Origin设置允许跨域的白名单,在白名单里的跨域请求是允许的。

Access-Control-Allow-Methods设置接受的方法,这里只接受POST方法。

Access-Control-Allow-Headers设置接受的请求头,用逗号分隔。

Access-Control-Allow-Max-Age设置预检的有效期,单位为秒。发送正式请求前,浏览器会预先发送一个预检请求,如果服务器返回了上述信息,表明是可以跨越请求的,然后才会正式发送请求。预检成功后,在有效期内就不用再发送了。

这里写图片描述

  1. 什么是跨域
    跨域,即跨站HTTP请求(Cross-site HTTP request),指发起请求的资源所在域不同于请求指向资源所在域的HTTP请求。
  2. 跨域的应用情景
    当使用前后端分离,后端主导的开发方式进行前后端协作开发时,常常有如下情景:

1.后端开发完毕在服务器上进行部署并给前端API文档。
2.前端在本地进行开发并向远程服务器上部署的后端发送请求。
在这种开发过程中,如果前端想要一边开发一边测试接口,就需要使用跨域的方式。

3. 通过注解的方式允许跨域
非常简单,我们可以在Controller类或其方法上加@CrossOrigin注解,来使之支持跨域。
举例:

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/User")
public class UserController {
}

其中origins为CrossOrigin的默认参数,即跨域来源,*即任何来源,也可以是其他域名。即可以以以下形式:

@CrossOrigin("http://test.com")
@CrossOrigin(origins="http://test.com",maxAge=3600)

该注解用于方法上,写法相同,处理时,SpringMVC会对类上标签和方法上标签进行合并。

4. 通过配置文件的方式允许跨域
在web.xml中添加如下配置:

	<filter-mapping>
        <filter-name>CorsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

使用这个Filter即可让整个服务器全局允许跨域。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是几种常见的解决跨域问题的代码示例: 1. CORS(服务端配置) 在服务端的响应中添加 CORS 相关的响应头,允许来自指定源的跨域请求。 ```java // Java - Spring Boot 示例 @Configuration public class CorsConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://example.com") // 允许的源地址 .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法 .allowedHeaders("*") // 允许的请求头 .allowCredentials(true); // 是否允许发送 cookie } }; } } ``` 2. JSONP(前端代码) 通过动态创建 `<script>` 标签来获取跨域数据。 ```javascript function handleResponse(data) { // 处理响应数据 } var script = document.createElement('script'); script.src = 'http://example.com/api?callback=handleResponse'; document.body.appendChild(script); ``` 3. 代理服务器(服务端代码) 通过服务器端代理转发请求,解决跨域问题。 ```javascript // Node.js - Express 示例 const express = require('express'); const request = require('request'); const app = express(); const API_URL = 'http://example.com/api'; app.get('/api', (req, res) => { const url = API_URL + req.url; req.pipe(request(url)).pipe(res); }); app.listen(3000, () => { console.log('Proxy server is running on port 3000'); }); ``` 4. WebSocket(前端代码) 使用 WebSocket 进行跨域通信。 ```javascript // 前端代码 const socket = new WebSocket('ws://example.com/socket'); socket.onopen = function() { // 连接成功,可以进行通信 socket.send('Hello Server!'); }; socket.onmessage = function(event) { // 处理接收到的消息 console.log('Received message:', event.data); }; ``` 这些示例代码只是简单的演示,实际解决跨域问题时,需要根据具体的应用场景和技术栈选择合适的解决方案。同时,还需注意安全性和适用性等方面的考虑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值