Làm cách nào để lấy url đầy đủ trong Express?


486

Giả sử url mẫu của tôi là

http://example.com/one/two

và tôi nói tôi có lộ trình sau

app.get('/one/two', function (req, res) {
    var url = req.url;
}

Giá trị của urlsẽ là /one/two.

Làm cách nào để có được url đầy đủ trong Express? Ví dụ, trong trường hợp trên, tôi muốn nhận http://example.com/one/two.


6
FYI bạn có thể kiểm tra đối tượng yêu cầu và xem qua nhưng tôi là một kẻ đạo đức giả và tìm thấy nó ở đây.
Jason Sebring

Câu trả lời:


742
  1. Giao thức có sẵn như là req.protocol. tài liệu ở đây

    1. Trước express 3.0, giao thức bạn có thể giả sử là httptrừ khi bạn thấy nó req.get('X-Forwarded-Protocol')được đặt và có giá trị https, trong trường hợp đó bạn biết đó là giao thức của mình
  2. Các máy chủ đến từ req.get('host')như Gopal đã chỉ ra

  3. Hy vọng rằng bạn không cần một cổng không chuẩn trong các URL của mình, nhưng nếu bạn cần biết thì bạn sẽ có nó trong trạng thái ứng dụng của mình bởi vì đó là bất cứ điều gì bạn chuyển đến app.listenvào lúc khởi động máy chủ. Tuy nhiên, trong trường hợp phát triển cục bộ trên một cổng không chuẩn, Chrome dường như bao gồm cổng trong tiêu đề máy chủ để req.get('host')trả về localhost:3000, chẳng hạn. Vì vậy, ít nhất là đối với các trường hợp của một trang web sản xuất trên một cổng tiêu chuẩn và duyệt trực tiếp đến ứng dụng cấp tốc của bạn (không có proxy ngược), hosttiêu đề dường như làm đúng về cổng trong URL.

  4. Đường dẫn đến từ req.originalUrl(cảm ơn @pgrassant). Lưu ý DOES này bao gồm chuỗi truy vấn. tài liệu ở đây trên req.url và req.origenUrl . Tùy thuộc vào những gì bạn định làm với URL, originalUrlcó thể hoặc không thể là giá trị chính xác so với req.url.

Kết hợp tất cả những thứ đó lại với nhau để xây dựng lại URL tuyệt đối.

  var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;

3
@dave khách hàng có thể gửi bất kỳ tiêu đề nào họ muốn (cũng như bất kỳ URL, cổng, rác không phải HTTP ngẫu nhiên nào), tuy nhiên, tại một số điểm không có thật hoặc tiêu đề không chính xác sẽ khiến giao thức bị lỗi. Ví dụ: trong môi trường máy chủ ảo, tiêu đề "máy chủ" không chính xác sẽ hiển thị một trang web hoàn toàn khác. Trong trường hợp X-Forwarded-Protocol, thường không được gửi bởi máy khách thực tế (trình duyệt) mà bằng proxy ngược (nginx / véc ni / apache / bất cứ thứ gì) đang phục vụ HTTPS trước ứng dụng của bạn.
Peter Lyons

59
Hoặc sử dụng req.get('Host')thay vì req.hostcung cấp cho máy chủ cộng với phần cổng.
diosney

1
Có lẽ tốt nhất để gửi một câu hỏi riêng cho điều đó. Câu hỏi này là về thể hiện.
Peter Lyons

18
Các hosttham số trong các tiêu đề yêu cầu có thể bị giả mạo. Có khả năng "tấn công tiêu đề máy chủ" nếu sử dụng res.hosttheo cách này. Trong khung Django, họ có một biến 'máy chủ được phép' được sử dụng để ngăn chặn cuộc tấn công đó. Tôi sử dụng một biến cấu hình là biến root_urlcó thể được thêm vào để req.urlhoàn thành. Về cuộc tấn công: skeletonscribe.net/2013/05/ từ
Amir Eldor

1
Nếu bạn muốn thêm req.originalUrlmà không có tham số, chỉ cần làm req.originalUrl.split("?").shift(). Nguồn: stackoverflow.com/a/32118818/2037431
Marcos Pereira

131

Thay vì tự mình kết hợp các thứ lại với nhau, thay vào đó, bạn có thể sử dụng API node.js cho các URL và chuyển URL.format()thông tin từ express.

Thí dụ:

var url = require('url');

function fullUrl(req) {
  return url.format({
    protocol: req.protocol,
    host: req.get('host'),
    pathname: req.originalUrl
  });
}

4
Trong trường hợp của tôi, req.get('host')trả về chỉ phần tên máy chủ , không phải cổng. Không biết tại sao, nhưng bây giờ tôi thu thập số cổng từ cài đặt và sử dụng hostnametrường thay vì host.
maxkoryukov

1
Thay vì pathname, tôi nghĩ bạn có ý nghĩa path. Bao gồm tìm kiếm / chuỗi truy vấn
Félix Sanz

3
Điều này không hoạt động đối với URL có chuỗi truy vấn.
Keith

37

Tôi tìm thấy một chút Pita để nhận url được yêu cầu. Tôi không thể tin rằng không có cách nào dễ dàng hơn trong việc thể hiện. Chỉ nên req.requested_url

Nhưng đây là cách tôi thiết lập nó:

var port = req.app.settings.port || cfg.port;
res.locals.requested_url = req.protocol + '://' + req.host  + ( port == 80 || port == 443 ? '' : ':'+port ) + req.path;

biến cổng có được xác định?
Amol M Kulkarni

4
req.porttồn tại? Nó không có trong tài liệu Express?
Mitar

Lỗi của tôi. Tôi giả sử bạn sẽ biết cổng nào bạn đang phục vụ và đặt cổng đó trước. Tôi sẽ cập nhật lại ví dụ. Bạn cũng có thể lấy nó vớireq.app.settings.port
chovy

khi req.protatio trống, có nghĩa là http?
Codebeat

Điều này không bao gồm các truy vấn. Nó chưa hoàn thành. Câu trả lời được chấp nhận là tốt hơn.
Kostanos

17

Sử dụng url.format :

var url = require('url');

Điều này hỗ trợ tất cả các giao thức và bao gồm số cổng. Nếu bạn không có chuỗi truy vấn trong tài liệu gốc, bạn có thể sử dụng giải pháp dọn dẹp này:

var requrl = url.format({
    protocol: req.protocol,
    host: req.get('host'),
    pathname: req.originalUrl,
});

Nếu bạn có một chuỗi truy vấn:

var urlobj = url.parse(req.originalUrl);
urlobj.protocol = req.protocol;
urlobj.host = req.get('host');
var requrl = url.format(urlobj);

16

Đây là một cách tuyệt vời để thêm một chức năng mà bạn có thể gọi vào đối tượng req để lấy url

  app.use(function(req, res, next) {
    req.getUrl = function() {
      return req.protocol + "://" + req.get('host') + req.originalUrl;
    }
    return next();
  });

Bây giờ bạn có một chức năng bạn có thể gọi theo yêu cầu nếu bạn cần nó.


2
Điều này không bao gồm người dùng: mật khẩu mà bạn có thể nhận được trong một url đầy đủ ' user: pass@host.com: 8080 / p / a / t / h? Query = string # hash '
Mã duy nhất

@Code Hoàn toàn đúng, nhưng vì quy ước đó đã bị từ chối trong hơn một thập kỷ nay, hy vọng không ai thực sự xây dựng thông số kỹ thuật userinfo vào API của họ
Mike

11

làm cho req.host/req.hostname có hiệu lực phải có hai điều kiện khi Express đằng sau proxy :

  1. app.set('trust proxy', 'loopback'); trong app.js
  2. X-Forwarded-Hosttiêu đề phải được chỉ định bởi bạn sở hữu trong máy chủ web. ví dụ. apache, nginx

nginx :

server {
    listen myhost:80;
    server_name  myhost;
    location / {
        root /path/to/myapp/public;
        proxy_set_header X-Forwarded-Host $host:$server_port;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://myapp:8080;
    }
}

apache :

<VirtualHost myhost:80>
    ServerName myhost
    DocumentRoot /path/to/myapp/public
    ProxyPass / http://myapp:8080/
    ProxyPassReverse / http://myapp:8080/
</VirtualHost>


1
vâng, không ai nói rằng, nếu bạn không có cấu hình chính xác trong apache hoặc nginx, bạn sẽ nhận được 127.0.0.1từreq.get('host')
Spark.Bao


7
var full_address = req.protocol + "://" + req.headers.host + req.originalUrl;

hoặc là

var full_address = req.protocol + "://" + req.headers.host + req.baseUrl;

6

Bạn cần xây dựng nó bằng cách sử dụng req.headers.host + req.url. Tất nhiên nếu bạn đang lưu trữ ở một cổng khác và như vậy bạn sẽ có ý tưởng ;-)


1
Điều đó mang lại cho tôi mọi thứ trừ giao thức ... có điều gì có thể cho tôi biết điều đó không?
Chris Abrams

Để có được giao thức, hãy sử dụng:req.protocol
ghi

6

Tôi sẽ đề nghị sử dụng originalUrl thay vì URL:

var url = req.protocol + '://' + req.get('host') + req.originalUrl;

Xem mô tả về bản gốcUrl tại đây: http://expressjs.com/api.html#req.origenUrl

Trong hệ thống của chúng tôi, chúng tôi làm một cái gì đó như thế này, vì vậy, gốcUrl rất quan trọng đối với chúng tôi:

  foo = express();
  express().use('/foo', foo);
  foo.use(require('/foo/blah_controller'));

blah_controll trông như thế này:

  controller = express();
  module.exports = controller;
  controller.get('/bar/:barparam', function(req, res) { /* handler code */ });

Vì vậy, URL của chúng tôi có định dạng:

www.example.com/foo/bar/:barparam

Do đó, chúng ta cần req.origenUrl trong bộ điều khiển thanh có trình xử lý.


6

Mã của tôi trông như thế này,

params['host_url'] = req.protocol + '://' + req.headers.host + req.url;


5

Tôi sử dụng gói nút 'url' (url cài đặt npm)

Những gì nó làm là khi bạn gọi

url.parse(req.url, true, true)

nó sẽ cung cấp cho bạn khả năng truy xuất tất cả hoặc một phần của url. Thêm thông tin ở đây: https://github.com/defunczombie/node-url

Tôi đã sử dụng nó theo cách sau để lấy bất cứ thứ gì có sau / in http://www.example.com/ để sử dụng như một biến và kéo lên một hồ sơ cụ thể (giống như facebook: http: //www.facebook. com / tên người dùng )

    var url = require('url');
    var urlParts = url.parse(req.url, true, true);
    var pathname = urlParts.pathname;
    var username = pathname.slice(1);

Mặc dù để điều này hoạt động, bạn phải tạo tuyến đường của mình theo cách này trong tệp server.js của bạn:

self.routes['/:username'] = require('./routes/users');

Và đặt tệp tuyến đường của bạn theo cách này:

router.get('/:username', function(req, res) {
 //here comes the url parsing code
}

2

Bạn có thể sử dụng chức năng này trong tuyến đường như thế này

app.get('/one/two', function (req, res) {
    const url = getFullUrl(req);
}

/**
 * Gets the self full URL from the request
 * 
 * @param {object} req Request
 * @returns {string} URL
 */
const getFullUrl = (req) => `${req.protocol}://${req.headers.host}${req.originalUrl}`;

req.protocolsẽ cung cấp cho bạn http hoặc https, req.headers.hostsẽ cung cấp cho bạn tên máy chủ đầy đủ như www.google.com, req.originalUrlsẽ cung cấp cho phần còn lại pathName(trong trường hợp của bạn /one/two)


Bạn có thể giải thích làm thế nào giải pháp này hoạt động. Tránh đăng mã chỉ trả lời trên Stack Overflow.
Arcath

@Arcath xây dựng.
Awais Ayub

1

Cảm ơn tất cả các thông tin này. Điều này là vô cùng khó chịu.

Thêm mã này vào mã của bạn và bạn sẽ không bao giờ phải suy nghĩ về nó nữa:

var app = express();

app.all("*", function (req, res, next) {  // runs on ALL requests
    req.fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl
        next()
})

Bạn cũng có thể làm hoặc đặt những thứ khác ở đó, chẳng hạn như đăng nhập vào bàn điều khiển.


0

Chỉ cần mã dưới đây là đủ cho tôi!

const baseUrl = `${request.protocol}://${request.headers.host}`;
// http://127.0.0.1:3333
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.