Vuejs 2.0 教程:与后端 API 进行交互
打赏作者

codedone

jelly,前后端分离后,要发布到生产环境是要怎么搞,直接将前端的代码,弄到laravel里面的模板中吗?

JellyBool 回复 codedone

前端代码就是 webpack 打包的js 吧,可以直接 build ,放到public 目录下

codedone 回复 JellyBool

好的,然后,用户进行http请求的话,是根据前端的路由去做转向?

JellyBool 回复 codedone

如果前后端分离的话,就是前端路由接管就可以

codedone 回复 JellyBool

好的,非常感谢jelly大大

leec

Vue前端项目 和 后端laravel api项目,分成两个不同文件夹放?
API可以弄成相对路径么?本地开发时候一个,联调测试时一个,只要前面的 base_api_url 不同。

JellyBool 回复 leec

base_api_url ? 没理解错的话,你可以设置 axios 的 baseUrl 的,只要你的 api 路由都是一致的话,就可以。

Vue前端项目 和 后端laravel api项目,分成两个不同文件夹放

这个倒是没什么要求吧,看你怎么放都可以。如果是在一个 laravel 项目里,你可以使用laravel 自带的 webpack ,也可以自己打包,build 之后,放到 public 目录

-SHERLOCK勋 回复 leec

可以放到webpack的env里面呀

sonics34

获取到文章ii

JellyBool 回复 sonics34

恩,可以的啊,直接作为路由参数就可以的。

话说怎么在这里问这个问题

liudong0763
//正确写法:
toggleComplete(todo){
                this.axios.patch('http://laravel.dev/api/todo/'+todo.id+'/completed').then(response=>{
                    console.log(response.data)
                    todo.completed = ! todo.completed
                })
            }
//可是为什么这样写就不正确呢
toggleComplete(todo){
                this.axios.patch('http://laravel.dev/api/todo/'+todo.id+'/completed').then(response=>{
                    console.log(response.data)
                    todo = response.data
                })
            }
JellyBool 回复 liudong0763

你具体看看你具体返回的是什么?

a119347 回复 liudong0763

第一个是直接把todocompleted取反,第二个是获取response的值,要加Json.parse()

etoupcom 回复 liudong0763

为什么新创建的数据点击completed无效呢?

JellyBool 回复 etoupcom

你看看 chrome devtool 报什么错误

etoupcom 回复 JellyBool

没有任何报错,添加新数据不刷新点击completed后没有反应,但是再点上面一条的completed两条会一起改变。刷新页面就没有这个问题。

JellyBool 回复 etoupcom

有可能是你添加数据的时候没有设置 completed 这个属性吧,你就打开 chrome devtool 看看整个流程

Arun 回复 etoupcom

你把completed传过去一起存数据库,然后就可以返回completed的值了

liudong0763
2laravel.dev/api/todo/8/completed:1 PATCH http://laravel.dev/api/todo/8/completed 
:8080/#/:1 XMLHttpRequest cannot load http://laravel.dev/api/todo/8/completed. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 429.
createError.js?f777:15 Uncaught (in promise) Error: Network Error(…)

老师,在我点complete按钮的时候,一般点前几次都没什么问题,但是点多几次就会在控制台报出这样的错误提示,不明白

JellyBool 回复 liudong0763
Uncaught (in promise) Error: Network Error(…)

网问题?

sfabric2016

这个系列后续还会更新吗?

JellyBool 回复 sfabric2016

恩,我应该今天就会更新

zovlqa 回复 JellyBool

Vue.js 20 后面的课程有什么计划呢(课程表),可以列出来么?

JellyBool 回复 zovlqa

后面应该是录两个跟 vuex 相关的视频吧

昝浩浩就是喜欢罗大霉

我听不懂怎么办…

JellyBool 回复 昝浩浩就是喜欢罗大霉

还好吧,我已经尽力说清楚了,貌似用户的评价还不错

ye0205414225

老师讲的非常好!赞叹呐!

是否之后会有个前后端分离(结合框架)打包放上开发环境流程详细教程呢?

JellyBool 回复 ye0205414225

这个也可以的,但是接下来我打算先录制一个实战的项目先

chunyi741

axios.get 可以正常获得数据,axios.post提示跨域请求

服务端路由

Route::post('api/todo/create', function (Request $request){
    $data = ['title' => $request->get('title'),'completed' => 0];
    $todo = App\Todo::create($data);
    return $todo;
})->middleware('cors');

TodoForm组件

methods: {
    addTodo(newTodo){
        this.axios.post(
        'http://localhost:8000/api/todo/create',{title: this.newTodo.title}).then(response => {
            console.log(response.data)
        })
        this.todos.push(newTodo);
        this.newTodo = {id:39,title:'',completed:false};
    },
}
JellyBool 回复 chunyi741

你的 laravel 版本是多少?api 路由的定义是否是在 api.php 里面?试试这样:

->middleware('cors','api');
chunyi741 回复 JellyBool

laravel版本是5.2

api 路由的定义是否是在 api.php 里面

你说的是api中间件吗,我并没有注册这个,我不知道应该怎么操作才能像你视频中说的在中间件中自动加上api/的路由前缀

JellyBool 回复 chunyi741

额,你的是 5.2 的版本的话,貌似你要使用 api 这个middleware。

chunyi741 回复 JellyBool

好的,下班了,回去仔细想一下,多谢Jelly

fujinshui

XMLHttpRequest cannot load http://192.168.0.168/tp5/public/index.php/admin/Todos/create. Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

JellyBool 回复 fujinshui

这是跨域问题引起的吧。视频应该有说到

fujinshui 回复 JellyBool

有用thinkphp吗 我get有值 post没值

fujinshui

addTodo(newTodo){
this.axios.post(‘http://192.168.0.168/tp5/public/index.php/admin/Todos/create’,{title:this.newTodo.title}).then(response=>{
console.log(response.data)
//this.todos.push(response.data);
})
this.newTodo={id:null,title:’’};
},后台接受值为空

xiaoshen 回复 fujinshui

视频里面程序有个bug,清空数据,第一次提交为id为null,程序会有问题;
还有视频里面把todo的id都设置null,让后台去控制id的生成,这样写好像有问题;

GOD_Nt

老师,如果前后端分离的话,像微信授权登录这种(结合overtrue/wechat)如何使用啊?

JellyBool 回复 GOD_Nt

具体我没有实现过,你可以看看这个讨论,感觉不错

https://pvg.v2ex.com/t/287376

GOD_Nt 回复 JellyBool

谢谢Jelly,这个和我理解的差不多,但是总感觉应该有更好的解决办法

墨生人

如果我想增删改成功以后,出现一个小弹窗,vue有没有相关的插件,或者本身自带这个功能?

JellyBool 回复 墨生人

删除完成之后触发一个 modal 就可以了吧,可以看看这个

https://vuejs.org/v2/examples/modal.html

墨生人 回复 JellyBool

好的,十分感谢

etoupcom

为什么新创建的数据点击completed无效呢

HideStone

看教程但是没有后端api 如何按照流程走呢,自己模拟数据吗?

JellyBool 回复 HideStone

你是说你完全不懂 后端?然后没有 api 数据?

HideStone 回复 JellyBool

对,没有接触过后端,那么与后端一系列的数据操作只有自己去模拟数据来完成吗?

JellyBool 回复 HideStone

这个有点难了,我帮你看看线上有没有类似的服务。

wenqingzzz

试验了好几次,我再进行get请求的时候没有什么问题,可是post请求的时候就会发生跨域的提示,不知道这个是怎么回事啊?我看了下请求method是OPTIONS的。
catch error提示 vue Error: Network Error

JellyBool 回复 wenqingzzz

使用了 cros 这个 package 了么

wenqingzzz 回复 JellyBool

使用了,我发现patch和delete都有报错

JellyBool 回复 wenqingzzz

vue Error: Network Error 这是什么鬼?你提供一下 chrome 的报错信息?

wenqingzzz 回复 JellyBool

Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8080’ is therefore not allowed access.

JellyBool 回复 wenqingzzz

这个就是跨域的吧,你使用了 cors 的路由怎么注册的?

wenqingzzz 回复 JellyBool

我在问答中描述了一下问题,感觉可能是设置的问题

lg23

群主: axios拦截器有讲没?
我想实现以下功能
统一处理所有http请求和响应
配置 http response inteceptor,当后端接口返回401 Unauthorzed(未授权),让用户重新登录

问题是我现在手工在浏览器中添加:
http://www.tb.com/api/order/type=0?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjUsImlzcyI6Imh0dHA6XC9cL3d3dy50Yi5jb21cL2FwaVwvbG9naW4iLCJpYXQiOjE0ODkyOTI4MDksImV4cCI6MTQ4OTI5NjQwOSwibmJmIjoxNDg5MjkyODA5LCJqdGkiOiI2OTNjYTY1MWU3MzVlZTQ4ODIxNWU2MzFkYzFjNTRjMSJ9.SV6yEcHkkALu07rSFdQx4ODm8zFrkNV7apxLYQg1MJc
请求返回结果是正常的。
但是我通过拦截器统一处理时,却总是提示:

GET http://www.tb.com/api/order/type=0 400 (Bad Request)
error : “token_invalid”

这里我估计是 token 没有添加上,但具体应该如何添加呢?

/**
 * 拦截器
 * 统一处理所有http请求和响应
 * 配置 http response inteceptor,当后端接口返回401 Unauthorzed(未授权),让用户重新登录
 */
import axios from 'axios'	// ajax 插件
import VueAxios from 'vue-axios' // vue请求ajax插件
import store from './vuex/store.js'//状态管理
import { USER_SIGNIN,USER_SIGNOUT,USER_REGISTER } from './vuex/types'// 引入状态定义 并解构
import router from './route-config.js'// 引入路由配置文件

// 全局 axios 默认值
// axios.defaults.baseURL = 'http://www.tb.com';

// 请求 拦截器
axios.interceptors.request.use(
	config => {
		console.log(Boolean(store.state.login.token))
		// 在请求之前做某事发送
		if (store.state.login.token) {// 判断是否存在token,如果存在,则每个http header都加上 token
			console.log(998112233)
		        // config.headers.Authorization = `token ${store.state.login.token}`;
			config.headers.Bearer = `token ${store.state.login.token}`;
		
		}
		console.log(config)
		return config;
	}, err => {// 发生错误
		return promise.reject(err);
	});

// 响应 拦截器
axios.interceptors.response.use(
	response => { // 对响应数据做某事
		console.log(123)
		return response;
	}, error => {
		if (error.response) {// 对响应错误做出反应
					console.log(789)
			switch (error.response.status) {
				case 401:
					// 401 清除token信息  并跳转到login
					store.commit(USER_SIGNOUT);
					router.replace({
						name: 'login',
						query: {redirect: router.currentRoute.fullPath}
					})
			}

			// 返回接口返回的错误信息
			return Promise.reject(error.response.data);
		}
			
	});

export default axios;

拦截器代码如上,还请指点!

JellyBool 回复 lg23

这根拦截器没什么关系吧

你用的apache is?nginx?

lg23 回复 JellyBool

nginx 服务器 php7.0

JellyBool 回复 lg23

bear 那行没写对…

config.headers.Beaer is= ’ Beaer $()…

lg23 回复 JellyBool

好的, 我试试

JellyBool 回复 lg23

这样试试:

config.headers.Bearer = `Bearer ${store.state.login.token}`;  
lg23 回复 JellyBool

群主!
这里的 Beaer 是不是 Bearer
另外 上面的 is 是什么意思?
Beaer 和 Bearer 我都试过,还是报一样的错误

config.headers.Bearer = `Bearer ${store.state.login.token}`;

报错如下:
GET http://www.tb.com/api/order/0 400 (Bad Request)
Uncaught (in promise) Object {error: “token_invalid”}

JellyBool 回复 lg23

保证这个 token 是可用的就行

${store.state.login.token}
lg23 回复 JellyBool

搞定了,我的写法是这样的

config.headers.Authorization = `Bearer ${store.state.login.token}`;
lg23 回复 JellyBool

我修改了添加token 的方法

if (store.state.login.token) {// 判断是否存在token,如果存在,则每个http header都加上 token
			
			reqHeaders.append('Authorization','Bearer '+store.state.login.token);
		}

目前没有报上面的错误了,但是返回数据时报错,提示
TypeError: Cannot read property ‘data’ of undefined

mounted() {// 生命周期钩子
		this.axios.get('http://www.tb.com/api/order/type=0')
		.then((response) => {
			console.log(JSON.parse(response.data))
		    //console.log(JSON.parse(response.data.resultData));
		    //this.lists = JSON.parse(response.data.resultData);
		})
	},

我后台返回的代码如下:
orderController.php
return $this->response->item($order, new OrderTransformer());

OrderTransformer.php
public function transform(Order $order)
	{
		// 调用 model 里的方法 将属性转换为数组
		return $order->attributesToArray();
	}
beaplat-61f

Laravel 5.1,路由使用 put 方法跨域有问题,改成 patch 就可以了

wuyutaott

jelly, api/todo/create 的认证是怎么实现的?

JellyBool 回复 wuyutaott

你说的是什么认证?

Alex 回复 wuyutaott

写一个controller即可,也可以使用vue的认证机制,前后台双向认证

lwQin

无法播放该视频,请换一个支持HTML5视频功能的浏览器
环境:Chrome58,win10

JellyBool 回复 lwQin

我看看,基本上是视频问题

dcharlie123

视频无法播放

a359611223

感觉再学习下去就想转前端了 哈哈哈哈

rabZhang

老师问一个比较幼稚的问题,是不是靠这样就能做网站了呢,就是做全栈的话,还需要学什么

JellyBool 回复 rabZhang

很多吧,部署站点会接触很多,nginx redis mysql 等

HsuChihYung

这个视频和第5个Vue和Laravel结合的视频会出现,“无法播放该视频,请换一个支持HTML5视频功能的浏览器”,用的是Chrome,有时会发生类似的情况,但有时也不会发生

masterJiaxing

我的vue里的patch无法请求到服务器,中间就403了

JellyBool 回复 masterJiaxing

你看看你的 middleware 呗

masterJiaxing 回复 JellyBool

不太明白这个是怎么回事,patch请求需要什么支持吗?还是使用cors建立的patch请求需要特殊配置

JellyBool 回复 masterJiaxing

patch 感觉不用什么特殊的要求。403 通常就是未认证的错误,经常就是 middleware 的问题

masterJiaxing

你说的未验证是csrf的问题吗?我设置了$except 'api/*'这样应该api里的请求都可以走吧?

JellyBool 回复 masterJiaxing

不是这个问题,通常是你的 middleware ,比如你使用了 auth:api 等,或者是你的 request 里面没有正确设置你的 authorized() 方法。

以后发问题的时候,把所有相关代码全部贴出来吧。不然我也看不出什么问题

masterJiaxing 回复 JellyBool
Route::patch('/todo/{id}/completed',function($id){//Request $request
       $article=App\Article::find($id);
        $article->completed=!$article->completed;
        $article->save();
        return $article;
    })->middleware('cors:api');
this.axios.patch('http://127.0.0.1/laravel/public/api/todo/'+ todo.id +'/completed').then(response=>{
                    console.info(response.data)
                    todo.completed=!todo.completed
                })

这段没法互通

XMLHttpRequest cannot load http://127.0.0.1/laravel/public/api/todo/10/completed. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 403.
JellyBool 回复 masterJiaxing

额,这个是跨域的问题吧。。。。

masterJiaxing 回复 JellyBool

嗯是的,cors这个中间件不是用来解决跨域问题的吗?有点蒙蔽的我

JellyBool 回复 masterJiaxing
middleware(‘cors’)

这样直接用呢

masterJiaxing 回复 JellyBool

像你这样单独用可以 了, middleware([‘api’,‘cors’]);这样写也可以用,我的 是5.2的版本

dppppp

老师 我看那个github上laravel-cors这个文档有变,我按照他的方法设置以后,在测试的时候,get的方式请求是ok的post还是会出现错误

XMLHttpRequest cannot load http://la51.me/api/tasks. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 500.
createError.js?8e8c:16 Uncaught (in promise) Error: Network Error
    at createError (createError.js?8e8c:16)
    at XMLHttpRequest.handleError (xhr.js?21f6:87)
dppppp
Route::group(['middleware'=>'api'],function(){
    Route::get('/api/tasks', function () {
        return \App\Task::all();
    });

    Route::get('/api/task/{id}', function ($id) {
        return \App\Task::find($id);
    });

    Route::post('/api/task/create', function () {
        return \App\Task::all();
    });
});
protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'api' => \Barryvdh\Cors\HandleCors::class,
    ];
Route::group(['middleware'=>'api'],function(){
    Route::get('/api/tasks', function () {
        return \App\Task::all();
    });

    Route::get('/api/task/{id}', function ($id) {
        return \App\Task::find($id);
    });

    Route::post('/api/task/create', function () {
        
    });
});

我用的是5.1这么写的

JellyBool 回复 dppppp

这个貌似是对 5.5 话 5.4 有升级

你看看安装 v0.8.6 版本的试试 https://github.com/barryvdh/laravel-cors/tree/v0.8.6

dppppp 回复 JellyBool
Route::group(['middleware' => 'cors'], function(\Illuminate\Routing\Router $router){
    $router->get('/api/tasks', function () {
        return \App\Task::all();
    });

    $router->get('/api/task/{id}', function ($id) {
        return \App\Task::find($id);
    });

    $router->post('/api/task/create',function(\Illuminate\Http\Request $request){
        return 111;
    });
});

改成这样了 还是get 好使 post 不好使

JellyBool 回复 dppppp

你看看你的 cors 的配置呗

dppppp 回复 JellyBool
'supportsCredentials' => false,
    'allowedOrigins' => ['*'],
    'allowedHeaders' => ['*'],
    'allowedMethods' => ['*'],
    'exposedHeaders' => [],
    'maxAge' => 0,
    'hosts' => [],

老师 你看这个有什么需要改的嘛?

JellyBool 回复 dppppp

感觉我实在看不出有什么错了。

'allowedMethods' => ['GET','POST'],

试试。

dppppp 回复 JellyBool

还是不行 /(ㄒoㄒ)/~~ 老师 你做这个视频的时候 用的la是什么版本啊 还有这个包是什么版本的啊?

JellyBool 回复 dppppp

Laravel 5.3 和 cors 0.8 的大版本

m2417599488 回复 JellyBool

hello jellybool.你浏览器解析json的插件是什么啊

JellyBool 回复 m2417599488

JSONFormmater ,貌似是这个

m2417599488 回复 JellyBool

多谢分享哦!

ronChenron

老师,我也按照你上面PHP的方法 写了路由配置 我不可以访问 IP/todos/create 的这个页面呢?是不是我忘记配置了什么?

ronChenron

这里是代码:

Route::post(’/todos/create’,function (Request $request){

 $data = ['title' => $request->get('title'),'completed'=>0];

 $todos = App\Models\Todo::create($data);

 return $todos;

})->middleware(‘cors’);

ronChenron

laravel 报错: MethodNotAllowedHttpException

JellyBool 回复 ronChenron

/todos/create 这个是 post 的路由啊

ronChenron 回复 JellyBool

呃呃呃~不是很明白问题出在了哪里,现在目前是只能够从数据库 获取 Todo这个表的数据 ,创建/修改/删除 貌似好像都不可以,我又看了文档 创建了一个控制器,把处理数据都放在contorller里面 但是还是不可以调用创建/修改/删除的方法

JellyBool 回复 ronChenron

/todos/create post 路由你用表单或者 ajax 的 post 访问这个地址就好

ronChenron 回复 JellyBool

现在是视频中的这个方法,换一个请求的方式就可以了吗?

this.axios.post(‘http://127.0.0.1:8000/todos/create’,{title:this.newTodo.title}).then((response)=>{
console.log(response.data)
})

JellyBool 回复 ronChenron
this.axios.post(‘http://127.0.0.1:8000/todos/create

这个应该没有什么问题吧。你直接地址栏访问是会报错的啊

zhangwei

完全前后交互不存在 俺先前说的bug了 也不知道咋回事 不过撸完了还挺有成就感

JellyBool 回复 zhangwei

俺先前说的bug了 也不知道咋回事
这是什么?

jam

看完感觉我要是只写laravel后台的API 还不够酷!! 还得会Vuejs !!

JellyBool 回复 jam

这两个结合,其实开发很多东西都非常方便。

liyingxuan

create这个按照之前视频配置:
->middleware(‘api’,‘cors’);
以上这种只配置了app.php中的aliases的使用方式GET是没有问题,但是POST是会出现跨域问题的。

解决方法:在./app/Http/Kernel.php中的protected $middleware 中增加:
\Barryvdh\Cors\HandleCors::class,

就可以解决POST跨域问题了。

seven2016

cors not works in laravel5.4!!!

seven2016 回复 JellyBool

找过了,都不行

liujun 回复 seven2016

我的5.6都可以

liujun

axios的get,delete请求的uri地址里的变量也可以用反引号引起来

liujun

个人建议:
laravel路由的uri里面没必要再加‘delete’,‘completed’等,因为restful形式的patch,delete请求已经很易读了。

f4cklangzi

我的代码是这样的,但是每次我去点击路由跳转的时候总是要触发到

  • 的点击事件,有没有什么办法办法可以阻止掉呢?

    <ul>
                <li :class="getClass(item)" v-for="(item,index) in list" @click="completeToggle(item)">{item.body}
                    <button @click.stop="del(index)">del</button>
                    <button><router-link :to="{name:'TodoDetail',params:{id:item.id}">detail</router-link></button>
                </li>
            </ul>
    

    找到解决办法了,在li的点击事件上使用@click.self="completeToggle(item)"

  • Flourishing

    @Jelly 你这里有个问题 当新建一个todo时 马上去点它的completed时 就出错了 刷新页面又可以 正常切换了todo的完成状态

    Asusua1

    jelly老师 这个todos的源码有吗?您的GitHub上好像找不到