Dynamically proxying of several pages in NuxtJS - proxy

In my NuxtJS application I has a folder with html pages, that can be added/deleted in any time from outside (/static/pages/page1.html, /static/pages/page2.html, ...) and I got a mapping to real uri's for this pages
{ '/foo': 'page1.html', '/bar': 'page2.html', ... }
I know I can use #nuxtjs/proxy, but it requires to rebuild an app every time mapping changes. I also know I can use nginx's rewrites for this, but changing it's config every time is painful too.
I also tried using 'pages/_.vue' file, read .html in component and place it's content to html using v-html, but files contains full html page (w/ scripts), and nuxt throw and error in this case, 'cos v-html don't allow using js (or maybe another reasons, which I can't understand)
How can I make dynamic proxy for this in NuxtJS?

For someone looking for answer for same question
Solve this by creating simple server middleware
in /pages_proxy/index.js:
const path = require('path');
const { Router } = require('express');
const express = require('express')
const app = express()
const router = Router()
router.get('*', async (req, res, next) => {
const pages = { '/foo/': 'page1.html', '/bar/': 'page2.html', ... }
const page = pages[req.path];
if (page) {
res.sendFile(path.join(__dirname, '../static/pages', page));
} else {
next();
}
});
app.use(router)
module.exports = app
in nuxt.config.js
serverMiddleware: {
'/': '~/pages_proxy'
},

Related

add API key to url

Hi I'm build a wildfire app tracker with react using the nasa API it works in development by using the url directly witch is https://eonet.sci.gsfc.nasa.gov/api/v2.1/events
But when I deploy it. It does not get the data. I obviously need a api key witch I have, but how do I implement it in the url above ?
here is my code..
useEffect(() => {
const fetchEvents = async () => {
setLoading(true)
const res = await fetch('https://eonet.sci.gsfc.nasa.gov/api/v2.1/events')
const {events} = await res.json()
setEventData(events)
setLoading(false)
}
fetchEvents()
// eslint-disable-next-line
}, [])
You could try to create a .env file in which you can set URLS as
REACT_APP_PUBLIC_URL=https://eonet.sci.gsfc.nasa.gov/api/v2.1/events
and then in your app component import as
fetch(process.env.REACT_APP_PUBLIC_URL)

Nuxt Axios Dynamic url

I manage to learn nuxt by using following tutorial
https://scotch.io/tutorials/implementing-authentication-in-nuxtjs-app
In the tutorial, it show that
axios: {
baseURL: 'http://127.0.0.1:3000/api'
},
it is point to localhost, it is not a problem for my development,
but when come to deployment, how do I change the URL based on the browser URL,
if the system use in LAN, it will be 192.168.8.1:3000/api
if the system use at outside, it will be example.com:3000/api
On the other hand, Currently i using adonuxt (adonis + nuxt), both listen on same port (3000).
In future, I might separate it to server(3333) and client(3000)
Therefore the api links will be
localhost:3333/api
192.168.8.1:3333/api
example.com:3333/api
How do I achieve dynamic api url based on browser and switch port?
You don't need baseURL in nuxt.config.js.
Create a plugins/axios.js file first (Look here) and write like this.
export default function({ $axios }) {
if (process.client) {
const protocol = window.location.protocol
const hostname = window.location.hostname
const port = 8000
const url = `${protocol}//${hostname}:${port}`
$axios.defaults.baseURL = url
}
A late contribution, but this question and answers were helpful for getting to this more concise approach. I've tested it for localhost and deploying to a branch url at Netlify. Tested only with Windows Chrome.
In client mode, windows.location.origin contains what we need for the baseURL.
# /plugins/axios-host.js
export default function ({$axios}) {
if (process.client) {
$axios.defaults.baseURL = window.location.origin
}
}
Add the plugin to nuxt.config.js.
# /nuxt.config.js
...
plugins: [
...,
"~/plugins/axios-host.js",
],
...
This question is a year and a half old now, but I wanted to answer the second part for anyone that would find it helpful, which is doing it on the server-side.
I stored a reference to the server URL that I wanted to call as a Cookie so that the server can determine which URL to use as well. I use cookie-universal-nuxt and just do something simple like $cookies.set('api-server', 'some-server') and then pull the cookie value with $cookies.get('api-server') .. map that cookie value to a URL then you can do something like this using an Axios interceptor:
// plguins/axios.js
const axiosPlugin = ({ store, app: { $axios, $cookies } }) => {
$axios.onRequest ((config) => {
const server = $cookies.get('api-server')
if (server && server === 'some-server') {
config.baseURL = 'https://some-server.com'
}
return config
})
}
Of course you could also store the URL in the cookie itself, but it's probably best to have a whitelist of allowed URLs.
Don't forget to enable the plugin as well.
// nuxt.config.js
plugins: [
'~/plugins/axios',
This covers both the client-side and server-side since the cookie is "universal"

Nuxt window is not defined on server-side rendering

I am trying to get the authorization headers from localStorage inside my middleware. Unfortunately this doesn't work on the first page load, because it is server-rendered.
How could I fix this?
const cookieName = 'feathers-jwt';
import { ApolloClient, createNetworkInterface } from 'apollo-client';
import 'isomorphic-fetch';
const API_ENDPOINT = 'http://localhost:3000/graphql';
const networkInterface = createNetworkInterface({ uri: API_ENDPOINT });
networkInterface.use([{
applyMiddleware(req, next) {
if (!req.options.headers) {
req.options.headers = {}; // Create the header object if needed.
}
req.options.headers['authorization'] = window.localStorage.getItem(cookieName);
next();
}
}]);
const apolloClient = new ApolloClient({
networkInterface,
transportBatching: true
});
export default apolloClient;
source: http://dev.apollodata.com/core/network.html
As I understand it, when you're rendering on the server you don't have access to window and document. In apps that render on both the server and in the client, you need to build in a check to see where you are, and handle that accordingly.
You can use this snippet for the detection of where you are:
var canUseDOM = !!(
typeof window !== 'undefined' &&
window.document &&
window.document.createElement
)
Use it to check if you are running server-side or client-side. In your case I would do the following:
If you're server-side you can check the cookies in the HTTP request itself;
If you're client-side you can check your localStorage store instead.
Of course, you can always opt to server-side render your website as an anonymous not authorised user by default. But that would cause the front-end to blink in and out of authorised state and would be annoying for the user.
In your case, I'd try to find authorisation cookies from the actual cookies that are present in your HTTP request.

UI Router not routing

I have an index.html file in the parent dir and with http://localhost:3000/#/ that's what's being loaded instead of the sidebar.html file. If I try http://localhost:300/#/home it redirects to todo
No errors being thrown.
app.js
'use strict';
angular
.module('App', [
'ui.router'
//'lbServices'
])
.run([ '$rootScope', '$state', '$stateParams',
function ($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
}])
.config(['$stateProvider','$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
title: 'Dashboard',
url: '/',
templateUrl: '../shared/sidebar/sidebar.html',
controller: 'sidebarCtrl'
});
$urlRouterProvider.otherwise('todo');
}]);
server.js
var loopback = require('loopback');
var boot = require('loopback-boot');
var app = module.exports = loopback();
// Set up the /favicon.ico
app.use(loopback.favicon());
// request pre-processing middleware
app.use(loopback.compress());
// -- Add your pre-processing middleware here --
// boot scripts mount components like REST API
boot(app, __dirname);
// -- Mount static files here--
// All static middleware should be registered at the end, as all requests
// passing the static middleware are hitting the file system
// Example:
var path = require('path');
app.use(loopback.static(path.resolve(__dirname, '../client')));
app.use(loopback.static(path.resolve(__dirname, '../node_modules')));
// Requests that get this far won't be handled
// by any middleware. Convert them into a 404 error
// that will be handled later down the chain.
app.use(loopback.urlNotFound());
// The ultimate error handler.
app.use(loopback.errorHandler());
app.start = function() {
// start the web server
return app.listen(function() {
app.emit('started');
console.log('Web server listening at: %s', app.get('url'));
});
};
// start the server if `$ node server.js`
if (require.main === module) {
app.start();
}
Not sure if this is related, but initially my server was set to listen on 0.0.0.0:3000 but if I typed that into the URL bar it went to Google search. Although if I type localhost:3000 it seemed to work. I have since changed the listening port to localhost:3000.
In case, that this url http://localhost:3000/#/, which should trigger state home - is loading index.html - should mean, that the path
templateUrl: '../shared/sidebar/sidebar.html',
is not set properly. Use the (e.g. chrome) developer tools and check if the sidebar.html is being loaded.
The fact that this url http://localhost:300/#/home is navigating to TODO state is also correct, becuase '/home' is not mapped to home state
.state('home', {
...
url: '/',
});
so the default is triggered
$urlRouterProvider.otherwise('todo');
NOTE: From the question, and described issue I expect that the index.html is set properly. It contains <div ui-view=""></div>, which will be filled with sidebar.html. That's why I would suspect the wrong path to that partial view template...

How to upload, display and save images using node.js and express

I need to upload an image, and display it, as well as save it so that I don't lose it when I refresh the localhost. This needs to be done using an "Upload" button, which prompts for a file-selection.
I am using node.js and express for the server-side code.
First of all, you should make an HTML form containing a file input element. You also need to set the form's enctype attribute to multipart/form-data:
<form method="post" enctype="multipart/form-data" action="/upload">
<input type="file" name="file">
<input type="submit" value="Submit">
</form>
Assuming the form is defined in index.html stored in a directory named public relative to where your script is located, you can serve it this way:
const http = require("http");
const path = require("path");
const fs = require("fs");
const express = require("express");
const app = express();
const httpServer = http.createServer(app);
const PORT = process.env.PORT || 3000;
httpServer.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
// put the HTML file containing your form in a directory named "public" (relative to where this script is located)
app.get("/", express.static(path.join(__dirname, "./public")));
Once that's done, users will be able to upload files to your server via that form. But to reassemble the uploaded file in your application, you'll need to parse the request body (as multipart form data).
In Express 3.x you could use express.bodyParser middleware to handle multipart forms but as of Express 4.x, there's no body parser bundled with the framework. Luckily, you can choose from one of the many available multipart/form-data parsers out there. Here, I'll be using multer:
You need to define a route to handle form posts:
const multer = require("multer");
const handleError = (err, res) => {
res
.status(500)
.contentType("text/plain")
.end("Oops! Something went wrong!");
};
const upload = multer({
dest: "/path/to/temporary/directory/to/store/uploaded/files"
// you might also want to set some limits: https://github.com/expressjs/multer#limits
});
app.post(
"/upload",
upload.single("file" /* name attribute of <file> element in your form */),
(req, res) => {
const tempPath = req.file.path;
const targetPath = path.join(__dirname, "./uploads/image.png");
if (path.extname(req.file.originalname).toLowerCase() === ".png") {
fs.rename(tempPath, targetPath, err => {
if (err) return handleError(err, res);
res
.status(200)
.contentType("text/plain")
.end("File uploaded!");
});
} else {
fs.unlink(tempPath, err => {
if (err) return handleError(err, res);
res
.status(403)
.contentType("text/plain")
.end("Only .png files are allowed!");
});
}
}
);
In the example above, .png files posted to /upload will be saved to uploaded directory relative to where the script is located.
In order to show the uploaded image, assuming you already have an HTML page containing an img element:
<img src="/image.png" />
you can define another route in your express app and use res.sendFile to serve the stored image:
app.get("/image.png", (req, res) => {
res.sendFile(path.join(__dirname, "./uploads/image.png"));
});

Resources