วิธีรับ URL เต็มใน Express


486

สมมติว่า URL ตัวอย่างของฉันคือ

http://example.com/one/two

และฉันบอกว่าฉันมีเส้นทางต่อไปนี้

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

ค่าของจะurl/one/two

ฉันจะได้URL แบบเต็มในเอ็กซ์เพรสได้อย่างไร http://example.com/one/twoยกตัวอย่างเช่นในกรณีข้างต้นผมอยากที่จะได้รับ


6
FYI คุณสามารถตรวจสอบวัตถุคำขอและตรวจสอบ แต่ฉันเป็นคนปากว่าตาขยิบและพบมันที่นี่
Jason Sebring

คำตอบ:


742
  1. โปรโตคอลมีให้ในreq.protocolรูปแบบ เอกสารที่นี่

    1. ก่อนแสดง 3.0 โพรโทคอลที่คุณสามารถสันนิษฐานได้httpเว้นแต่ว่าคุณเห็นว่าreq.get('X-Forwarded-Protocol')มีการตั้งค่าและมีค่าhttpsซึ่งในกรณีนี้คุณรู้ว่าเป็นโปรโตคอลของคุณ
  2. โฮสต์มาจากreq.get('host')ที่ระบุไว้ใน Gopal

  3. หวังว่าคุณไม่จำเป็นต้องใช้พอร์ตที่ไม่ได้มาตรฐานใน URL ของคุณ แต่ถ้าคุณไม่จำเป็นต้องรู้ว่ามันจะมีอยู่ในสถานะแอปพลิเคชันของคุณเพราะมันเป็นสิ่งที่คุณผ่านไปapp.listenเมื่อเซิร์ฟเวอร์เริ่มต้น อย่างไรก็ตามในกรณีของการพัฒนาท้องถิ่นบนพอร์ตที่ไม่ได้มาตรฐานดูเหมือนว่า Chrome จะรวมพอร์ตในส่วนหัวของโฮสต์เพื่อให้req.get('host')ส่งคืนlocalhost:3000ตัวอย่างเช่น ดังนั้นอย่างน้อยสำหรับกรณีของไซต์ที่ใช้งานจริงบนพอร์ตมาตรฐานและเรียกดูโดยตรงไปยังแอปด่วนของคุณ (ไม่มีพร็อกซีย้อนกลับ) hostส่วนหัวจึงดูเหมือนจะทำสิ่งที่ถูกต้องเกี่ยวกับพอร์ตใน URL

  4. เส้นทางมาจากreq.originalUrl(ขอบคุณ @pgrassant) หมายเหตุนี้ไม่รวมถึงสตริงแบบสอบถาม เอกสารที่นี่ใน req.url และ req.originalUrl ทั้งนี้ขึ้นอยู่กับสิ่งที่คุณตั้งใจจะทำอย่างไรกับ URL ที่อาจหรือไม่อาจจะเป็นค่าที่ถูกต้องเมื่อเทียบกับoriginalUrlreq.url

รวมสิ่งเหล่านั้นทั้งหมดเข้าด้วยกันเพื่อสร้าง URL ที่แน่นอนขึ้นมาใหม่

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

3
@ บันทึกลูกค้าสามารถส่งสิ่งที่ต้องการส่วนหัว (เช่นเดียวกับสิ่งใด URL, พอร์ต, ขยะที่ไม่ใช่ HTTP แบบสุ่ม) อย่างไรก็ตามในบางจุดปลอมหรือส่วนหัวที่ไม่ถูกต้องก็จะทำให้โปรโตคอลล้มเหลว ตัวอย่างเช่นในสภาพแวดล้อมโฮสต์เสมือนส่วนหัว "โฮสต์" ที่ไม่ถูกต้องจะแสดงเว็บไซต์ที่แตกต่างอย่างสิ้นเชิง ในกรณีของ X-Forwarded-Protocol ที่มักจะไม่ส่งโดยไคลเอนต์จริง (เบราว์เซอร์) แต่โดยพร็อกซีย้อนกลับ (nginx / varnish / apache / อะไรก็ตาม) ที่ให้บริการ HTTPS หน้าแอปพลิเคชันของคุณ
Peter Lyons

59
หรือใช้req.get('Host')แทนreq.hostซึ่งจะให้โฮสต์รวมถึงส่วนพอร์ต
diosney

1
อาจเป็นการโพสต์คำถามแยกต่างหากที่ดีที่สุด คำถามนี้เกี่ยวกับด่วน
Peter Lyons

18
hostพารามิเตอร์ในส่วนหัวของคำขอสามารถหัวหมุน อาจมี "การโจมตีส่วนหัวของโฮสต์" ที่เป็นไปได้หากใช้res.hostวิธีนี้ ในกรอบ Django พวกเขามีตัวแปร 'อนุญาตโฮสต์' ที่ใช้เพื่อป้องกันการโจมตีดังกล่าว ฉันใช้ตัวแปรการกำหนดค่าที่เป็นของฉันroot_urlซึ่งสามารถเพิ่มในการreq.urlทำให้เสร็จสมบูรณ์ได้ เกี่ยวกับการโจมตี: skeletonscribe.net/2013/05/…
Amir Eldor

1
หากคุณต้องการที่จะเพิ่มโดยไม่มีพารามิเตอร์เพียงแค่ทำreq.originalUrl req.originalUrl.split("?").shift()ที่มา: stackoverflow.com/a/32118818/2037431
Marcos Pereira

131

แทนที่จะต่อสิ่งต่าง ๆ เข้าด้วยกันด้วยตัวคุณเองคุณสามารถใช้node.js API แทน URLและส่งURL.format()ข้อมูลจาก express

ตัวอย่าง:

var url = require('url');

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

4
ในกรณีของฉันreq.get('host')คืนค่าเฉพาะชื่อโฮสต์ส่วนไม่ใช่พอร์ต ไม่ทราบว่าทำไม แต่ตอนนี้ฉันรวบรวมหมายเลขพอร์ตจากการตั้งค่าและใช้ข้อมูลแทนhostname host
maxkoryukov

1
แทนที่จะผมคิดว่าคุณหมายถึงpathname pathซึ่งรวมถึงการค้นหา / การสืบค้น
Félix Sanz

3
สิ่งนี้ใช้ไม่ได้กับ URL ที่มีสตริงข้อความค้นหา
Keith

37

ฉันพบ PITA เล็กน้อยเพื่อรับ URL ที่ร้องขอ ฉันไม่อยากจะเชื่อว่าไม่มีวิธีที่ง่ายกว่าในการแสดง ควรเป็น req.requested_url

แต่นี่คือวิธีที่ฉันตั้งไว้:

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

ต้องกำหนดตัวแปรพอร์ต
Amol M Kulkarni

4
ไม่req.portอยู่? ไม่ได้อยู่ในเอกสาร Express?
Mitar

ความผิดฉันเอง. ฉันสันนิษฐานว่าคุณจะรู้ว่าพอร์ตใดที่คุณให้บริการอยู่และตั้งค่าก่อนหน้านี้ ฉันจะอัปเดตตัวอย่างอีกครั้ง นอกจากนี้คุณยังสามารถรับได้ด้วยreq.app.settings.port
chovy

เมื่อ req.protocol ว่างเปล่าหมายความว่า http หรือไม่
Codebeat

อันนี้ไม่รวมถึงแบบสอบถาม มันไม่สมบูรณ์ คำตอบที่ยอมรับได้ดีกว่า
Kostanos

17

ใช้url.format :

var url = require('url');

รองรับโปรโตคอลทั้งหมดและรวมถึงหมายเลขพอร์ต หากคุณไม่มีสตริงการสืบค้นในต้นฉบับของคุณคุณสามารถใช้น้ำยาทำความสะอาดนี้:

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

หากคุณมีสตริงการสืบค้น:

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

16

นี่เป็นวิธีที่ยอดเยี่ยมในการเพิ่มฟังก์ชั่นที่คุณสามารถเรียกใช้บนวัตถุ req เพื่อรับ url

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

ตอนนี้คุณมีฟังก์ชั่นที่คุณสามารถโทรหาได้ถ้าต้องการ


2
ไม่รวมถึงผู้ใช้: รหัสผ่านที่คุณสามารถรับได้ใน url เต็มรูปแบบ ' user: pass@host.com: 8080 / p / a / t / h? query = string # hash '
รหัส Uniquely

@CodeUniquely จริง แต่เนื่องจากการประชุมที่ได้รับการคัดค้านมานานกว่าทศวรรษในขณะนี้หวังว่าจะไม่มีใครสร้างรายละเอียด userinfo ลงใน API ของพวกเขา
Mike

11

ทำให้ req.host/req.hostname มีประสิทธิภาพต้องมีสองเงื่อนไขเมื่อExpress behind พร็อกซี :

  1. app.set('trust proxy', 'loopback'); ใน app.js
  2. X-Forwarded-Hostส่วนหัวจะต้องระบุโดยคุณเป็นเจ้าของในเว็บเซิร์ฟเวอร์ เช่น. 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;
    }
}

อาปาเช่ :

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


1
อ๋อไม่มีใครบอกว่าถ้าคุณไม่มีการกำหนดค่าที่ถูกต้องใน apache หรือ nginx คุณจะได้รับ127.0.0.1จากreq.get('host')
Spark.Bao


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

หรือ

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

6

req.headers.host + req.urlคุณต้องการที่จะสร้างได้โดยใช้ แน่นอนถ้าคุณกำลังโฮสต์ในพอร์ตอื่นและเช่นคุณได้รับแนวคิด ;-)


1
นั่นทำให้ฉันทุกอย่าง แต่โปรโตคอล ... มีอะไรที่บอกได้ไหม
Chris Abrams

ในการรับโปรโตคอลใช้:req.protocol
mrded

6

ฉันอยากจะแนะนำให้ใช้ originalUrl แทน URL:

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

ดูคำอธิบายของ originalUrl ที่นี่: http://expressjs.com/api.html#req.originalUrl

ในระบบของเราเราทำอะไรแบบนี้ดังนั้นค่าดั้งเดิมคือสิ่งสำคัญสำหรับเรา:

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

blah_controller มีลักษณะเช่นนี้:

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

ดังนั้น URL ของเราจึงมีรูปแบบ:

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

ดังนั้นเราต้องการ req.originalUrl ในตัวควบคุมแถบรับตัวจัดการ



5

ฉันใช้แพคเกจโหนด 'url' (การติดตั้ง npm)

เมื่อคุณโทรหาคุณ

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

มันจะทำให้คุณมีความเป็นไปได้ที่จะดึง URL ทั้งหมดหรือบางส่วน ข้อมูลเพิ่มเติมที่นี่: https://github.com/defunctzombie/node-url

ฉันใช้มันในวิธีต่อไปนี้เพื่อให้ได้สิ่งที่ตามมา / ในhttp://www.example.com/เพื่อใช้เป็นตัวแปรและดึงโปรไฟล์บางอย่างขึ้นมา (เช่น like facebook: http: //www.facebook com / ชื่อผู้ใช้ )

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

แม้ว่าจะใช้งานได้ แต่คุณต้องสร้างเส้นทางของคุณด้วยวิธีนี้ในไฟล์ server.js ของคุณ:

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

และตั้งค่าไฟล์เส้นทางของคุณด้วยวิธีนี้:

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

2

คุณสามารถใช้ฟังก์ชั่นนี้ในเส้นทางเช่นนี้

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.protocolจะให้ http หรือ https req.headers.hostแก่คุณจะให้ชื่อโฮสต์แบบเต็มเช่น www.google.com req.originalUrlจะให้ส่วนที่เหลือpathName(ในกรณีของคุณ/one/two)


คุณช่วยอธิบายวิธีการแก้ปัญหานี้ให้ละเอียด หลีกเลี่ยงการโพสต์รหัสคำตอบเฉพาะใน Stack Overflow
Arcath

@Arcath ทำรายละเอียดเพิ่มเติม
Awais Ayub

1

ขอบคุณทุกท่านสำหรับข้อมูลนี้ มันน่ารำคาญอย่างไม่น่าเชื่อ

เพิ่มไปยังรหัสของคุณและคุณจะไม่ต้องคิดถึงมันอีก:

var app = express();

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

คุณสามารถทำหรือตั้งสิ่งอื่น ๆ ที่นั่นเช่นกันเช่นล็อกเพื่อคอนโซล


0

แค่โค้ดด้านล่างก็เพียงพอแล้วสำหรับฉัน!

const baseUrl = `${request.protocol}://${request.headers.host}`;
// http://127.0.0.1:3333
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.