moleculerjs / moleculer-web

:earth_africa: Official API Gateway service for Moleculer framework
http://moleculer.services/docs/moleculer-web.html
MIT License
294 stars 118 forks source link

assets not work #55

Closed roytan883 closed 6 years ago

roytan883 commented 6 years ago

as Doc , i config it like this:

assets: {
          // Root folder of assets
          folder: "./public",

          // Options to `server-static` module
          options: {}
        },

Then i write a index.html in ./public/index.html, But i try those URL, all can't get the index.html

/index.html
/api/index.html
/api/public/index.html
/api/public/api/public/index.html
/api/api/public/index.html
icebob commented 6 years ago

Please show the full settings.

roytan883 commented 6 years ago

To fix this issue, i create my own static middleware, and it works

let staticMiddleware = function (req, res, next) {
  if (_.startsWith(req.url, '/api/static')) {
    //must change the url prefix to map to static folder root
    let oldUrl = req.url
    req.url = _.replace(req.url, '/api/static/', '/');
    console.log(`staticMiddleware change req.url: [${oldUrl}] -> [${req.url}]`)
    serve(req, res, finalhandler(req, res))
  }
  else {
    next()
  }
}

To enable Dir access, need modify the error hander:

onError(req, res, err) {
          if (!_.startsWith(req.url, '/api/static') && _.endsWith(req.url, '/')) {
            res.writeHead(302, {
              'Location': '/api/static' + req.url
            })
            res.end();
            return
          }
          res.setHeader("Content-Type", "text/plain");
          res.writeHead(err.code || 500);
          res.end('Error: ' + err.message);
        }
roytan883 commented 6 years ago

the issue settings:

 mixins: [ApiService],
 settings: {
   path: "/api",
   assets: {
          // Root folder of assets
          folder: path.join(__dirname, "./public"),

          // Options to `server-static` module
          options: {}
        },
icebob commented 6 years ago

It should work with this settings. Similar code in examples and it works.

roytan883 commented 6 years ago

and i found that // Global-level middlewares in settings is not really GLOBAL. It only handle request from /api

roytan883 commented 6 years ago

@icebob

It should work with this settings. Similar code in examples and it works.

which url should i use to access index.html in assets folder ? /index.html /api/index.html /api/assets/index.html

icebob commented 6 years ago

if you have a root path: "/api", in this case /api/index.html. If no root path, just /index.html.

roytan883 commented 6 years ago

OK, it works. But root path is /api, the access path need to be /index.html.

icebob commented 6 years ago

Hmm it's weird. Maybe it doesn't consider the path setting.

roytan883 commented 6 years ago

But i think it is great. assets path should not start with /api. Please do not change it :)

roytan883 commented 6 years ago

@icebob But use the assets settings did not use compression() middleware which i config at global middleware

roytan883 commented 6 years ago

I think the assets not use compression , because the root level middleware is not GLOBAL so far, which only handle /api

icebob commented 6 years ago

Global middlewares are added to routes only, not for global static serving. In this case you'd better make a path: "/" route where you can add compression & serve static middlewares instead of global assets.

roytan883 commented 6 years ago

so the global assets can't use compression ?

roytan883 commented 6 years ago

why not make the Global middlewares apply to GLOBAL ? (I mean on /) So far, if setting the root path is /api, then all i can hook is on this path, all other /xxx can't handle. Its not extendable.

roytan883 commented 6 years ago

So far, I found the only interface I can hook to GLOBAL is onError ......

roytan883 commented 6 years ago

So the right way to use this library is : root path: / route1: /api route2: /assets If it is right, then the global assets setting does not make any sence.

icebob commented 6 years ago

No the route can be / too.

root path: / route1: /api route2: / (must be the latest)

icebob commented 6 years ago

Can I make an example settings?

roytan883 commented 6 years ago

yes, please.

icebob commented 6 years ago

It's a snippet from my real project:

"use strict";

module.exports = {
    name: "www",
    mixins: [ApiGateway],

    settings: {
        path: "", // fixed

        port: process.env.PORT || 3000,

        use: [
            compression(),
            // Security
            helmet(),
        ],

        routes: [
            /**
             * API route
             */
            {
                path: "/api",

                // Action aliases
                aliases: {
                    // Users
                    "REST /users": "users",
                },

                // Disable to call not-mapped actions
                mappingPolicy: "restrict",

                // Use bodyparser modules
                bodyParsers: {
                    json: { limit: "2MB" },
                    urlencoded: { extended: true, limit: "2MB" }
                },
            },

            /**
             * Static route
             */
            {
                path: "/",

                use: [
                    // Serve static
                    ApiGateway.serveStatic("./public"),

                    // Favicon
                    favicon("./public/favicon.ico")
                ],

                // Action aliases
                aliases: {
                },

                mappingPolicy: "restrict",
            }
        ]
    }
};

The routes:

roytan883 commented 6 years ago

not work ...... here is code: ApiGatewayService ->

class ApiGatewayService extends Service {
  constructor(broker) {
    super(broker);
    this.parseServiceSchema({
      name: "apiGateway",
      mixins: [ApiGateway],

      settings: {
        path: "/",

        port: 10300,

        use: [
          compression(),
          // Security
          // helmet(),
        ],

        routes: [
          /**
           * API route
           */
          {
            path: "/api",
            mappingPolicy: "all",
            // Use bodyparser modules
            bodyParsers: {
              json: { limit: "2MB" },
              urlencoded: { extended: true, limit: "2MB" }
            },
          },

          /**
           * Static route
           */
          {
            path: "/",

            use: [
              // Serve static
              ApiGateway.serveStatic("./public"),
            ],
          }
        ]
      }
    });
  }
  async serviceCreated() {
    this.logger.info(`${this.name} Service created.`);
  }
  async serviceStarted() {
    this.logger.info(`${this.name} Service started.`);
  }
  async serviceStopped() {
    this.logger.info(`${this.name} Service stopped.`);
  }
}
module.exports = ApiGatewayService;

main.js

//new moleculer broker
let broker = new ServiceBroker({
  namespace: config.namespace,
  nodeID: config.nodeID,
  requestTimeout: config.natsTimeout,
  logger: console,
  logLevel: config.logLevel,
  logFormatter: logFormatter,
  transporter: {
    type: "NATS",
    options: {
      url: config.natsHost,
      // user: "admin",
      // pass: "123"
    }
  },
  statistics: true,
});

//load service
broker.loadService(path.join(__dirname, `./services/${config.service}`, '/index.js'))

//start
broker.start().then(() => {
  console.warn(`=====[${config.nodeID}]=====>>>>> started`)
})

open /index.html return

{
  "name": "MoleculerError",
  "message": "Not found",
  "code": 404
}

a strange thing is Service created never print. But my other services printed, does ApiGateway not support by loadService?

icebob commented 6 years ago

Which versions?

icebob commented 6 years ago

a strange thing is Service created never print. But my other services printed, does ApiGateway not support by loadService?

You should set functions in parseSchema

            created: this.serviceCreated,
            started: this.serviceStarted,
            stopped: this.serviceStopped,
roytan883 commented 6 years ago

Now the /api works weird:

      name: "apiGateway",
      mixins: [ApiGateway],
      settings: {
        path: "/",
        port: 10300,
        use: [
          compression(),
        ],

        routes: [
          {
            path: "/api",
            bodyParsers: {
              json: { limit: "2MB" },
            },
          },

call curl -H "Content-Type:application/json" -X POST -d '{"name": "roy"}' http://127.0.0.1:1030/api/demo/welcome return:

{
  "name": "MoleculerError",
  "message": "Not found",
  "code": 404
}

But call curl -H "Content-Type:application/json" -X POST -d '{"name": "roy"}' http://127.0.0.1:1030//api/demo/welcome it works, return:

"Welcome, roy :)"

you see, the // works ...

icebob commented 6 years ago

Which versions are you using?

roytan883 commented 6 years ago

version:

"name": "moleculer-web",
  "version": "0.6.4",
icebob commented 6 years ago

Try it:

      name: "apiGateway",
      mixins: [ApiGateway],
      settings: {
        path: "",
roytan883 commented 6 years ago

I just installed it yesterday

roytan883 commented 6 years ago

OK, set path: "", make both /api and static assets work

icebob commented 6 years ago

Great, I will fix this path: "/" issue in the next version

roytan883 commented 6 years ago

Thanks for your help 👍