react+axios用node代理解决跨域

今天自己搭了个react架子,网上找了个公开的接口,结果发现跨域了。因为接口是别人的,我没法让别人在接口上处理跨域问题,而且这个接口是post请求方式,也没发用jsop处理跨域。

一、前端处理跨域

1、利用proxy代理

特点:这种方式简单易用,不受接口类型限制,get,post等都能支持,适用于与前后端分离的项目。

使用方式:
找到package.json文件,在里面加上 proxy:代理接口地址,重新启动项目即可。

 "proxy": "http://10.99.206.102:9992/api/v1"
proxy

需要注意的是,若使用本方法代理跨域,且开启了全局配置的公共接口地址,一定记得将公共接口地址配置为空。我项目一般使用的axios,需要将这个全局配置改为空。axios.defaults.baseURL = ""
随便请求一个接口,看看接口是不是走的自己电脑的ip或者localhost,若不是就证明代理跨域没成功,检查下接口配置有没有清理。

2、利用jsonp处理get请求

若只是想处理单个get请求的跨域,直接使用jsonp方式即可。这个项目中基本没用,有需要的话,自己百度看看怎么操作的。

二、node代理跨域

总体思路,就是直接让node去掉这个跨域的接口(因为服务器端不存在跨域,所以node调用接口是没毛病的),拿到结果。然后在node端抛出这个路由,前端调用这个接口就可以了。但是我的react是脚手架启动的,并不是我写的node启动的,所以端口还是不一样,这样还是有跨域问题,这时候的跨域问题就很好解决了,在后端配置下cros就好了。

当然,这种方式比较麻烦,一般工作中后台直接处理跨域就可以了,不需要单独再启动node处理跨域。这里就是记录下node一个完整的调用过程,java处理跨域也是一样开启一个cros即可。

闲话不多说,我直接把代码附上,然后把写代码过程中遇到的问题总结下。
我调用的公共接口是 图灵机器人 里的接口

接口地址:

http://www.tuling123.com/openapi/api
怎么用这个接口,可以直接看图灵机器人官网,上面说的很清楚。

我是直接用create-react-app搭建的项目,然后把src下面的目录都删掉,自己建了两个文件,index.js和index.css
最终的文件目录结构如下:


文件目录

src/index.js文件如下:

import React from 'react'
import ReactDOM from 'react-dom'
import axios from 'axios'
import  './index.css'
class Layout extends React.Component{
    constructor(){
        super()
        this.state={
            content:'',
            value:'zoey'
        }
    }
 componentDidMount(){
        let data1
    axios.post('http://www.tuling123.com/openapi/api',{
       info:'今天我最美',
       userId:1234
    }).then(data=>{
        console.log(data)
        data1 = data
    })

      this.setState({
       content:data1
      })
   }
    render(){
        debugger
        const obj = this.state.content
        let one = []
        for( var item in obj){
           one.push( item=='text'? obj[item]:'')
         }
            return <div>
            <header className='header'>我是头部信息</header>
            <div>{one}</div>
        </div>  
    }
}

ReactDOM.render(
    <Layout/>,
    document.querySelector('#root')
)

这里就会发现报错


跨域

因为同源策略,导致这里跨域,我就开始搭建了个node服务器,代码如下:
建了个文件夹server,里面新建3个文件server.js routes.js home.js
server/server.js的代码:

const Koa= require('koa')
const app = new Koa()
const routes = require('./routes.js');
//路由
app.use(routes());
app.listen(3001,()=>{
    console.log('port is running at 3001')
})

server/routes.js的代码

const compose = require('koa-compose');
const Router = require('koa-router');
var router = new Router();
const Home = require('./home');
router.get('/api/index', Home.index)
 
// app.use(router.routes()).use(router.allowedMethods());
module.exports = (ctx, next) => compose([router.routes(), router.allowedMethods()]);

server/home.js的代码:

const axios = require('axios')
class Home {
    static async index(ctx,next){
        const {info,userId} =ctx.request.query
     const {data} = await  axios.post('http://www.tuling123.com/openapi/api',{
            key:'c9d1eb9811e648a49ece24b7cb1065e9',
            info:info,
            userId:userId
        })
         console.log(data)
         ctx.body=data
    }
}
module.exports = Home

然后启动这个server,为了方便我就没配置,直接手动切换到server目录下,node server.js启动项目,这样这个服务器就抛出了可以localhost:3001/api/index这个接口了,这个接口返回的结果就是我们所需的了。
现在改改src/index.js中componentDidMount中的代码

 componentDidMount(){
        let data
      //注意,这里3001 就是node启用的端口
      axios.get('http://localhost:3001/api/index',{
        params:{ info:'今天我最美',
        userId:1234}
     }).then(req=>{
     {data} = req
})
       this.setState({
        content:data
       })
    }

这里你就发现一个问题了,又一次出现了跨域,那现在这个跨域就很好解决了,配置下服务端代码就可以了,我直接在server/server.js中用了koa-cros这个插件就可以啦,这里注意,cors一定要放在路由的上面。

const Koa= require('koa')
const app = new Koa()
const routes = require('./routes.js');
const cors = require('koa2-cors'); 
//运行跨域
app.use(cors());  
//路由
app.use(routes());
app.listen(3001,()=>{
    console.log('port is running at 3001')
})

配置好了以后,又发现data取不到数据,这里因为axios是异步的,数据还没有获取,页面已经渲染完成了。因为axios返回的是一个promise,所以这里可以把componentDidMount改成异步等待的方法,取得data的值

   async componentDidMount(){
        //注意,这里3001 就是node启用的端口
     const {data}=  await axios.get('http://localhost:3001/api/index',{
        params:{ info:'今天我最美',
        userId:1234}
     })

       this.setState({
        content:data
       })
    }

这样数据就能显示了

在调用过程中发现我对于post方式里的Content-Type 的参数不是很清楚,下面我总结下Content-Type 几种常用的参数的使用场景:(这里为转载)

application/x-www-form-urlencoded

这应该是最常见的 POST 提交数据的方式了。浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样

POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8
title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。例如 PHP 中,_POST[‘title’] 可以获取到 title 的值,_POST[‘sub’] 可以得到 sub 数组。

很多时候,我们用 Ajax 提交数据时,也是使用这种方式。例如 JQuery 和 QWrap 的 Ajax,Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8」。

multipart/form-data

这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 form 的 enctyped 等于这个值。直接来看一个请求示例:

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"

title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 mutipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 –boundary 开始,紧接着内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 –boundary– 标示结束。关于 mutipart/form-data 的详细定义,请前往 rfc1867 查看。

这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段原生 form 表单也只支持这两种方式。但是随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利。

application/json

application/json 这个 Content-Type 作为响应头用来告诉服务端消息主体是序列化后的 JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。

JSON 格式支持比键值对复杂得多的结构化数据,这一点也很有用。
例如下面这段代码:

var data = {'title':'test', 'sub' : [1,2,3]};
$http.post(url, data).success(function(result) {
   ...
});

最终发送的请求是:

POST http://www.example.com HTTP/1.1
Content-Type: application/json;charset=utf-8

{"title":"test","sub":[1,2,3]}

这种方案,可以方便的提交复杂的结构化数据,特别适合 RESTful 的接口。各大抓包工具如 Chrome 自带的开发者工具、Firebug、Fiddler,都会以树形结构展示 JSON 数据,非常友好。但也有些服务端语言还没有支持这种方式,例如 php 就无法通过 $_POST 对象从上面的请求中获得内容。这时候,需要自己动手处理下:在请求头中 Content-Type 为 application/json 时,从 php://input 里获得原始输入流,再 json_decode 成对象。

text/xml

它是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范。XML-RPC 协议简单、功能够用,各种语言的实现都有。JavaScript 中,也有现成的库支持以这种方式进行数据交互,能很好的支持已有的 XML-RPC 服务。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容