跨域请求:Fetch实现跨域请求与POST方式参数提交

一、要实现跨域,首先需要理解什么叫做跨域。

跨域是指,不同域名之间相互访问。
例如 :我的电脑上有2个服务器 192.168.0.11  192.168.0.12  
如果第一个服务器上的页面要访问第二个服务器,就叫做跨域  
或者http://www.baidu.com 要访问http://www.xxx.com ,也是不同域名,也是跨域  
明白什么叫做跨域之后就可以想怎么解决这个问题了。要实现跨域就需要明白跨域资源共享协议:CORS。
要详细了解CORS,请参照一下博客地址,这里就不再赘述。

参考博客:

跨域资源共享 CORS 详解(http://www.ruanyifeng.com/blog/2016/04/cors.html)

二、解决跨域

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

以下以SPRING+React+ Fetch进行示例。

上面也说了,CORS需要浏览器和服务器同时支持,那么服务器如何支持跨域呢。

如果服务器是apache

(1)修改http服务的配置文件:C:\wamp\bin\apache\Apache2.4.4\conf\httpd.conf

LoadModule headers_module modules/mod_headers.so前面的注释删除.

(2)添加Header set Access-Control-Allow-Origin *

<Directory />

    AllowOverride none

    Require all granted

         Header set Access-Control-Allow-Origin *

</Directory>

(3)重启http服务

如果是tomcat,比如spring MVC项目

首先要创建一个Filter拦截器进行拦截
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

public class CorsFilter implements Filter{

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

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;  
        response.setHeader("Access-Control-Allow-Origin", "*");  
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");  
        response.setHeader("Access-Control-Allow-Headers", "token,Access-Control-Allow-Origin,Access-Control-Allow-   Methods,Access-Control-Max-Age,authorization");
        chain.doFilter(req, res);
        
    }

    @Override
    public void destroy() {
    }

}

关键代码:response.setHeader("Access-Control-Allow-Origin", "*");

修改web.xml,增加:

<filter>  
      <filter-name>corsFilter</filter-name>  
      <filter-class>=**.**.CorsFilter</filter-class>  
    </filter>  
    <filter-mapping>  
      <filter-name>corsFilter</filter-name>  
      <url-pattern>*.json</url-pattern>  
    </filter-mapping>

**.**需要用自己的类路径代替

上面服务器支持跨域了,下面开始前端页面进行跨域请求

import xFetch from './xFetch';

export default class UserService {
  constructor(options) {
  }


  getUserList(callback) {
    let formData = new FormData();
    formData.append("groupId", 1);

    var init = {
        method: 'POST',
        mode:'cors',
        cache: 'default',
        headers: {
          'Accept': 'application/x-www-form-urlencoded',
          'Access-Control-Allow-Origin':'*',
          'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT, DELETE',
          'token': '**********'
        },
        body:formData
      };
    xFetch('http://127.0.0.1:8080/**/**/**.json',init
    ).then(
      ({jsonResult}) => {
        /*
        jsonResult.map(item => {
          alert(item.title);
        })*/
        callback(jsonResult, {});
      }
    );
  }

  getUserHoldRoleList(callback) {
    xFetch('/userHoldRoleList').then(
      ({jsonResult}) => {
        /*
        jsonResult.map(item => {
          alert(item.title);
        })*/
        callback(jsonResult, {});
      }
    );
  }
}


注意:以上服务器端Filter设置里面
       response.setHeader("Access-Control-Allow-Origin", "*");  
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");  
        response.setHeader("Access-Control-Allow-Headers", "token,Access-Control-Allow-Origin,Access-Control-Allow-      Methods,Access-Control-Max-Age,authorization");

与前端页面请求中

let formData = new FormData();
    formData.append("groupId", 1);

    var init = {
        method: 'POST',
        mode:'cors',
        cache: 'default',
        headers: {
          'Accept': 'application/x-www-form-urlencoded',
          'Access-Control-Allow-Origin':'*',
          'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT, DELETE',
          'token': 'Cl5bxjcUt+gDtIDJY4wDgZKNoYdMcgjKQQKXga/UKtmpfniucZTeKaf5mUjsm7uc'
        },
        body:formData
      };


的header要保持一致。

其中method 表示请求的方法。而允许哪些方法呢,在headers中是有设置的,服务器端和前端都有设置,而且需要相同

'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT, DELETE',

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

表示前端要在header中传递的参数和使用的参数

   response.setHeader("Access-Control-Allow-Headers", "token,Access-Control-Allow-Origin,Access-Control-Allow-   Methods,Access-Control-Max-Age,authorization");


mode 方式指定了使用的协议,这里写了使用 cors协议。mode 请求的方式 cors, no-cors, or same-origin

cache 缓存 default, no-store, reload, no-cache, force-cache, or only-if-cached

headers 这个参数需要用到 Headers 对象。

'Access-Control-Allow-Origin':'*'  也是在服务器端和前端中都有设置。 这个代表的意思是 允许访问的域名。*  表示允许跨所有,为了安全起见,可以设置为固定的域名。 这样 服务器端与客户端就进行了双向的域名绑定。


REACT 使用POST方式进行提交


我们在请求http接口时候,通常都会使用get和post的方式,针对表单提交这类的请求,我们通常采用post方式。

那么在RN中的Fetch API中post提交有哪些坑呢?让我们撸起来。


我们先来说说Server端的代码,通常我们从Request获取参数时的方法为:

  1. String paraValue = request.getParameter(paraName);  
我们下面说的判断能不能获取参数,就是按照这种方法来获取。

在 RN中,通常我们会怎么写代码呢?
方案一(不推荐)
[javascript] view plain copy
  1. let url = "http://127.0.0.1:8080/api/testFetch”  
  2. let params = "name=admin&password=admin123”;  
  3. fetch(url , {  
  4.   method: 'POST',  
  5.   headers: {},  
  6.   body: params,  
  7. }).then((response) => {  
  8.   if (response.ok) {  
  9.       return response.json();  
  10.   }  
  11. }).then((json) => {  
  12.   alert(JSON.stringify(json));  
  13. }).catch((error) => {  
  14.   console.error(error);  
  15. });  

此时我们发现在Server端无法获取到name和password的值。
换成GET试试,将params追加到url后,发现ok。那这是什么情况呢?下面讲解。

好,不行,我们就再换一种方法试试呗。
方案二(不推荐):
[javascript] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. let params = {"name":"admin","password":"admin123"};  
  2.   
  3. fetch(url , {  
  4.   method: 'POST',  
  5.   headers: {},  
  6.   body:JSON.stringify(params),  
  7. }).then((response) => {  
  8.   if (response.ok) {  
  9.       return response.json();  
  10.   }  
  11. }).then((json) => {  
  12.   alert(JSON.stringify(json));  
  13. }).catch((error) => {  
  14.   console.error(error);  
  15. });  
我们直接将params封装成一个JSON对象,然后在body里将JSON对象转成字符串传过去,发现然并卵,Server端还是获取不到值。


好,我们不兜圈子了,直接说明原因。
其实,方案一和方案二都是直接在body里传递了一个字符串,在Server端获取body的方式如下:
  1. StringBuilder buffer = new StringBuilder();  
  2. BufferedReader reader = beat.getRequest().getReader();  
  3. String line;  
  4.  while ((line = reader.readLine()) != null) {  
  5.     buffer.append(line);  
  6.  }  
  7. String body = buffer.toString();  
通过这种方法我们可以获取到传入的字符串。
既然能获取到字符串,那么我们也可以拿到我们传入的值了,可以转JSON、或者按&切割字符串,只不过这种解决方案好像有点挫啊!!!

也许你会问在jquery中,我们就是按照方案一这种方式做的啊,怎么好使呢?
答:因为参数 "name=admin&password=admin123” 在jquery中,传入对象框架会自动封装成formData的形式,fetch没有这个功能。

终极方案(推荐使用):

既然fetch不会自动转FormData,那我们自己new一个FormData,直接传给body。
在FormData中也可以传递字节流实现上传图片的功能。参考: http://blog.csdn.net/codetomylaw/article/details/52446786
[javascript] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. let formData = new FormData();  
  2. formData.append("name","admin");  
  3. formData.append("password","admin123");  
  4.   
  5. etch(url , {  
  6.  method: 'POST',  
  7.  headers: {},  
  8.  body: formData,  
  9. ).then((response) => {  
  10.  if (response.ok) {  
  11.      return response.json();  
  12.  }  
  13. ).then((json) => {  
  14.  alert(JSON.stringify(json));  
  15. ).catch((error) => {  
  16.  console.error(error);  
  17. );  
这样我们就可以在Server端获取到name和password的值了。


参考博客:

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

https://www.giuem.com/html5-fetch-api/

http://www.cnblogs.com/snandy/p/5076512.html

http://blog.csdn.net/u012620506/article/details/52346264

http://blog.csdn.net/codetomylaw/article/details/52588493






  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值