O Vue Router é fundamental para gerenciar a navegação em aplicações Vue.js, oferecendo benefícios significativos.
Principais Vantagens do Vue Router:
- Carregamento Lento de Componentes: Melhora a velocidade de carregamento inicial da página, carregando componentes apenas quando são necessários.
- Controle de Acesso: Atua como um ponto centralizado para verificações de autenticação, prevenindo acesso não autorizado e permitindo gerenciamento granular de permissões.
- Gerenciamento de Estado: Sincroniza o estado da aplicação com a URL, suportando nativamente as funcionalidades de avançar/retroceder do navegador e facilitando o compartilhamento de links para páginas específicas.
- Organização do Código: Centraliza a lógica de navegação das páginas, tornando o código mais fácil de manter e expandir, além de proporcionar uma estrutura clara das relações entre as páginas.
Escopo de Atuação do Router:
O Vue Router é responsável exclusivamente pela navegação entre páginas. Ele não lida com requisições de API. O fluxo é:
Operação do Usuário → Vue Router → Renderização de Componente.
Requisições de API (via Axios/Fetch) ocorrem independentemente do roteador.
Exemplos de atuação do router:
/login→ Exibe a página de login./article/manage→ Exibe a página de gerenciamento de artigos.- Monitoramento e tratamento de mudanças no endereço do navegador.
Definição e Uso de Rotas:
As definições de rota especificam o mapeamento entre caminhos e componentes:
const rotas = [
{ path: '/login', component: LoginComponent },
{
path: '/',
component: LayoutComponent,
redirect: '/article/manage',
children: [
{ path: '/article/category', component: ArticleCategory },
{ path: '/article/manage', component: ArticleManagement },
{ path: '/article/avatar', component: UserAvatar },
{ path: '/article/info', component: UserInfo },
{ path: '/article/resetPassword', component: UserPasswordReset }
]
}
];
A navegação programática é feita através do objeto router:
const handleMenuClick = (command) => {
if (command === 'logout') {
authStore.clearToken();
router.push('/login');
} else if (command === 'profile') {
router.push('/article/info');
} else if (command === 'avatar') {
router.push('/article/avatar');
} else if (command === 'password') {
router.push('/article/resetPassword');
}
};
O fluxo real de uma requisição de API envolve:
- Chamada de método no componente.
- Função de serviço de API (ex:
userService.login). - Instância Axios configurada (ex:
apiClient.js). - Interceptors de requisição (tratamento de Token).
- Envio da requisição HTTP para o backend.
- Interceptors de resposta (tratamento do resultado).
- Retorno para o componente.
Mecanismo dos "Guards" de Rota:
Os "guards" de rota (como beforeEach) funcionam como verificações globais antes de cada transição de rota.
router.beforeEach((to, from, next) => {
// Verifica se o destino é a página de login
if (to.path === '/login') {
next(); // Permite a navegação
return;
}
// Verifica a existência do token de autenticação
const authStore = useAuthStore(); // Assumindo um store para autenticação
if (!authStore.isAuthenticated) {
next('/login'); // Redireciona para o login
return;
}
next(); // Permite a navegação normal
});
As seguintes ações disparam as verificações dos guards:
router.push('/article/manage')router.replace('/login')window.location.href = '/'
As requisições diretas via Axios ou Fetch não passam pelos guards de rota:
axios.get('/api/users')fetch('/api/articles')
Interceptors de Requisição e Resposta:
Os interceptors do Axios permitem intervir em requisições antes de serem enviadas e nas respostas antes de serem tratadas pela aplicação.
import axios from 'axios';
import { ElMessage } from 'element-plus';
import { useAuthStore } from '@/stores/auth'; // Assumindo um store de autenticação
const API_BASE_URL = '/api';
const apiClient = axios.create({ baseURL: API_BASE_URL });
// Interceptor de Requisição
apiClient.interceptors.request.use(
(config) => {
const authStore = useAuthStore();
if (authStore.token) {
config.headers.Authorization = `Bearer ${authStore.token}`;
}
return config;
},
(error) => {
ElMessage.error(`Erro na requisição: ${error.message}`);
return Promise.reject(error);
}
);
// Interceptor de Resposta
apiClient.interceptors.response.use(
(response) => {
// Assume que o código 0 indica sucesso
if (response.data.code === 0) {
return response.data;
}
// Trata falhas com base na mensagem do backend
ElMessage.error(response.data.msg || 'Erro no serviço');
return Promise.reject(response.data);
},
(error) => {
ElMessage.error(error.message || 'Erro no serviço');
return Promise.reject(error);
}
);
export default apiClient;
Gerenciamento de Tokens com Pinia:
Utiliza-se o Pinia para gerenciar o estado do token de autenticação, permitindo persistência loccal.
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useAuthStore = defineStore('auth', () => {
const token = ref('');
const setToken = (newToken) => {
token.value = newToken;
};
const clearToken = () => {
token.value = '';
};
return { token, setToken, clearToken };
}, {
// Persiste o estado no localStorage
persist: true,
});
A configuração persist: true garante que o token permaneça disponível mesmo após o recarregamento da página ou o fechamento e reabertura do navegador, utilizando o localStorage por padrão.
No entanto, essa abordagem local não resolve:
- Expiração do Token no Backend: O tempo de vida definido no servidor.
- Riscos de Segurança: Armazenamento a longo prazo em armazenamento local.
- Revogação Ativa: Necessidade de limpar o token em caso de logout manual.
A gestão completa da expiração de tokens requer colaboração entre frontend e backend. O frontend deve verificar periodicamente a validade do token e limpar tokens expirados. O backend deve definir tempos de expiração razoáveis e retornar códigos de status apropriados (como 401). Mecanismos como "refresh tokens" podem ser implementados para melhorar a experiência do usuário, permitindo a renovação automática do token sem intervenção.